Guide · Jobs data

Greenhouse, Lever, Ashby and Workday jobs API: the free endpoints and their gotchas

Greenhouse, Lever and Ashby each publish a public, keyless JSON feed of a company's open jobs. You need the company's board token, which is usually the last part of its job-board URL. Workday works differently, and has its own section below.

The endpoints

ATS Endpoint Shape
Greenhouse GET https://boards-api.greenhouse.io/v1/boards/{token}/jobs (?content=true adds descriptions, departments, offices) {"jobs": [...], "meta": {"total": N}}
Lever GET https://api.lever.co/v0/postings/{token}?mode=json (EU accounts: api.eu.lever.co) bare JSON array
Ashby GET https://api.ashbyhq.com/posting-api/job-board/{token} (?includeCompensation=true adds pay) {"apiVersion": "1", "jobs": [...]}

Gotchas

import requests

def greenhouse(token):
    r = requests.get(f"https://boards-api.greenhouse.io/v1/boards/{token}/jobs", timeout=20)
    r.raise_for_status()
    return [{"id": j["id"], "title": j["title"], "location": j["location"]["name"],
             "posted": j.get("first_published"), "url": j["absolute_url"]} for j in r.json()["jobs"]]

def lever(token, eu=False):
    host = "api.eu.lever.co" if eu else "api.lever.co"
    r = requests.get(f"https://{host}/v0/postings/{token}?mode=json", timeout=20)
    r.raise_for_status()
    return [{"id": p["id"], "title": p["text"], "location": p["categories"].get("location"),
             "posted": p.get("createdAt"), "url": p["hostedUrl"]} for p in r.json()]

def ashby(token):
    r = requests.get(f"https://api.ashbyhq.com/posting-api/job-board/{token}", timeout=20)
    r.raise_for_status()
    return [{"id": j["id"], "title": j["title"], "location": j["location"],
             "posted": j.get("publishedAt"), "url": j["jobUrl"]}
            for j in r.json()["jobs"] if j.get("isListed", True)]

for name, jobs in [("greenhouse:stripe", greenhouse("stripe")),
                   ("lever:spotify", lever("spotify")),
                   ("ashby:ramp", ashby("ramp"))]:
    print(name, len(jobs), jobs[0]["title"] if jobs else "-")

For daily "new jobs" alerts, diff job IDs against yesterday's run rather than trusting dates, because reposted jobs get fresh dates. To find tokens, see how to scrape Greenhouse jobs without a browser.

Workday jobs API

Workday has no public job-board feed like the three above. Each career site ({tenant}.wd{N}.myworkdayjobs.com/{site}) loads its jobs from its own search endpoint, which you can call too: POST /wday/cxs/{tenant}/{site}/jobs with a JSON body. It isn't documented as a public API, so expect changes, keep requests slow and respect the site's robots.txt.

What trips people up:

import time, requests

def workday(host, tenant, site, search=""):
    url = f"https://{host}/wday/cxs/{tenant}/{site}/jobs"
    jobs, offset, total = [], 0, None
    while True:
        r = requests.post(url, json={"appliedFacets": {}, "limit": 20, "offset": offset,
                                     "searchText": search}, timeout=20)
        r.raise_for_status()
        data = r.json()
        if total is None:
            total = data["total"]           # only reliable on the first page
        page = data["jobPostings"]
        if not page:
            break
        jobs += [{"title": j["title"], "location": j.get("locationsText"),
                  "posted": j.get("postedOn"), "path": j["externalPath"]}
                 for j in page if j.get("title") and j.get("externalPath")]   # skip non-public stubs
        offset += 20
        time.sleep(1)
        if offset >= min(total, 2000):
            break
    return total, jobs

total, jobs = workday("TENANT.wd5.myworkdayjobs.com", "TENANT", "SITE")
print(total, "on the board,", len(jobs), "read")
print(jobs[:3])

We built this

Disclosure: Your Evenings Ltd built and sells this. Greenhouse, Lever, Ashby & Workday Jobs API is a pay-per-use Actor on the Apify Store that does all of this for a list of company domains:

It doesn't cover other systems (for example iCIMS or SuccessFactors) yet.

Longer walkthrough: Greenhouse jobs API: get jobs posted in the last 24 hours (and why your scraper returns 0 jobs) on dev.to.

FAQ

Is there a free Greenhouse jobs API? Yes. boards-api.greenhouse.io/v1/boards/{token}/jobs is public and keyless for reading published jobs.

Do Lever and Ashby need an API key for job postings? No. Both posting APIs are public for reading.

Does Workday have a public jobs API? Not a documented one. Career sites use their own search endpoint, which returns at most 2,000 results per search and shows only approximate posted dates.

Product names and logos belong to their owners. Your Evenings Ltd is not affiliated with or endorsed by them.