Most tech companies don't host their own job listings. They use an applicant tracking system (ATS), and the big ones (Greenhouse, Lever and Ashby) each expose a public job-board feed that powers the company's careers page. If you want job data for a list of companies, these feeds beat scraping LinkedIn or Indeed: they're the source of truth, they're structured, and they don't block you.
The catch: every ATS is different
-
Greenhouse boards live at
boards.greenhouse.io/<board>; pay ranges only appear if you ask for them and the company publishes them. -
Lever boards live at
jobs.lever.co/<company>, with "commitment" and "workplaceType" fields and a different salary shape. -
Ashby boards live at
jobs.ashbyhq.com/<company>and often include compensation, in yet another format.
And you first need to know which ATS a company uses. "Stripe" doesn't tell you that.
Option 1: do it yourself
For a single ATS, it's a few lines of requests against the public board endpoint plus a mapping function. Multiply that by eight platforms, add platform detection, salary parsing from free text, seniority inference and de-duplication for "new jobs only", and it becomes a small project to maintain.
Option 2: one normalised API
Disclosure: I built this. I wrapped all of that into a hosted API on Apify that takes company names, careers URLs or platform:board pairs and returns one schema for all eight platforms:
from apify_client import ApifyClient
client = ApifyClient("<YOUR_APIFY_TOKEN>")
run = client.actor("cape-data-labs/company-career-jobs-api").call(
run_input={"companies": ["https://boards.greenhouse.io/airbnb", "lever:palantir", "ashby:ramp"]}
)
for job in client.dataset(run["defaultDatasetId"]).iterate_items():
print(job["company"], job["title"], job["workplaceType"], job["salary"])
Each job comes back with title, department, location, remote/hybrid/on-site, seniority, employment type, salary (min/max/currency/period), posted date and apply URL. Turn on onlyNewJobs and schedule it daily for alerts; you only pay for postings you haven't seen ($1.50 per 1,000 jobs).
More examples (CSV export, Slack alerts, remote-with-salary search, hiring-intent lead scoring): https://github.com/andrevs/ats-jobs-api-examples
What I learned building it
- Platform detection by name is a guessing game; careers-page URLs are always faster and more reliable.
- Pay ranges are more common than you'd think: in one test run, 145 of Ramp's 171 open roles had one. But every ATS stores them differently.
- Job ads are a surprisingly good technographic source: companies name their CRM, warehouse and cloud in them. That became a second API, Hiring Signals.
Top comments (0)