How to get all open jobs from Greenhouse, Lever and Ashby career pages

# jobs# recruiting# api# python
How to get all open jobs from Greenhouse, Lever and Ashby career pagesHay Equipos

Pull 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.

What you get back

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..."
}
Enter fullscreen mode Exit fullscreen mode

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.

How to find a company's job board slug

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.

Step by step in the Apify Console

  1. Open the actor on the Apify Store and start it in the Console.
  2. In Companies, add one company per line, in any of these forms:
    • a job board URL, such as https://boards.greenhouse.io/airbnb or https://jobs.lever.co/spotify
    • ats:slug, such as ashby:ramp
    • a plain slug, such as ramp, and the actor tries each system in turn
  3. Add filters if you want them: Title contains any of, Title contains none of, Location contains any of, Department or team contains any of, Remote jobs only, and Posted within the last N days.
  4. Turn Include full job description off for a lighter output.
  5. Set Maximum jobs per company (default 500) and Maximum jobs in total (default 5,000).
  6. Click Start and export as CSV, Excel, JSON or HTML.

Calling it from code

curl:

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}'
Enter fullscreen mode Exit fullscreen mode

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"])
Enter fullscreen mode Exit fullscreen mode

To monitor new jobs, schedule the actor daily with postedWithinDays set to 1 or 2, or compare jobId values between runs.

Pricing

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.

Limits and what it does not do

  • Six systems only. Workday, iCIMS, Taleo, SuccessFactors and custom career sites are not covered.
  • Salary appears only when the company publishes it. Ashby and Greenhouse often include ranges, Lever and Recruitee sometimes, Workable and SmartRecruiters rarely through these APIs.
  • Posted date is what the job board reports. Workable gives a date without a time.
  • A plain slug can match a different company with the same slug on another system. Use the full board URL or ats:slug when that matters.
  • SmartRecruiters needs one extra request per job for the description, so large SmartRecruiters boards are slower with descriptions on.
  • It does not collect personal data about candidates or recruiters.

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