Hay EquiposPull every open role from company job boards on Greenhouse, Lever, Ashby, Workable, SmartRecruiters and Recruitee into one table with salary and apply links.
If you track hiring at a list of companies, whether as a recruiter, a job board, a sales team looking for hiring signals or an analyst, you quickly find that every careers page is different. Some run on Greenhouse, some on Lever or Ashby, some on Workable, and each shows jobs in its own layout. Checking them by hand every week does not scale.
The ATS Jobs API, published by Hay Equipos on the Apify Store, reads the public job board APIs that Greenhouse, Lever, Ashby, Workable, SmartRecruiters and Recruitee provide so companies can show their jobs anywhere. Give it a list of companies and it returns every open role in one schema: title, department, location, remote flag, salary range when published, posted date, job link, apply link and the description as plain text. No login, no browser.
One row per job, the same fields for every system (illustrative values):
{
"source": "greenhouse",
"companySlug": "examplecorp",
"company": "Example Corp",
"jobId": "4012345",
"title": "Senior Data Engineer",
"department": "Engineering",
"location": "London, United Kingdom",
"isRemote": false,
"workplaceType": "Hybrid",
"postedAt": "2026-09-15T09:00:00.000Z",
"salaryMin": 80000,
"salaryMax": 95000,
"salaryCurrency": "GBP",
"jobUrl": "https://boards.greenhouse.io/examplecorp/jobs/4012345",
"applyUrl": "https://boards.greenhouse.io/examplecorp/jobs/4012345#app",
"descriptionText": "About the role\n\nYou will build..."
}
A RUN_SUMMARY record in the key value store lists every company you asked for, which system it was found on, how many jobs were open and how many were saved, so a wrong slug stands out.
Open the company's careers page and click any job. The link usually shows both the system and the slug. A link like jobs.lever.co/spotify/... means Lever with the slug spotify, so you can write lever:spotify. A link on boards.greenhouse.io/airbnb means Greenhouse with the slug airbnb. If a company returns zero jobs, it either has no open roles right now or uses a system this actor does not cover; the run summary tells you which.
https://boards.greenhouse.io/airbnb or https://jobs.lever.co/spotify
ats:slug, such as ashby:ramp
ramp, and the actor tries each system in turncurl:
curl -X POST \
"https://api.apify.com/v2/acts/pistachio_implementation~ats-jobs-api/run-sync-get-dataset-items" \
-H "Authorization: Bearer $APIFY_TOKEN" \
-H "Content-Type: application/json" \
-d '{"companies": ["lever:spotify", "ashby:ramp"], "titleKeywords": ["engineer"], "postedWithinDays": 30, "includeDescription": false}'
Python with apify-client:
import os
from apify_client import ApifyClient
client = ApifyClient(os.environ["APIFY_TOKEN"])
run = client.actor("pistachio_implementation/ats-jobs-api").call(
run_input={
"companies": ["https://boards.greenhouse.io/airbnb", "lever:spotify", "ashby:ramp"],
"titleKeywords": ["engineer", "data"],
"locationKeywords": ["United States", "Remote"],
"postedWithinDays": 30,
"maxJobsPerCompany": 200,
}
)
for job in client.dataset(run["defaultDatasetId"]).iterate_items():
pay = f'{job.get("salaryMin")} to {job.get("salaryMax")} {job.get("salaryCurrency")}' if job.get("salaryMin") else ""
print(job["company"], job["title"], job["location"], pay, job["jobUrl"])
To monitor new jobs, schedule the actor daily with postedWithinDays set to 1 or 2, or compare jobId values between runs.
Pay per event: $0.001 per job saved, which is $1 per 1,000 jobs. No start fee and no platform usage charged on top. Companies that are not found, and jobs removed by your filters, cost nothing. A company with 150 open roles costs about 15 cents. You can set a maximum charge per run and the actor stops early when it is reached.
ats:slug when that matters.Please use the job data in line with each job board's terms.
Try it on the Apify Store: https://apify.com/pistachio_implementation/ats-jobs-api