Most applicant-tracking systems publish their job boards as public JSON. No login, no HTML parsing, no headless browser. Here is how to use them, and when a ready-made tool is worth it.
The three public endpoints
| ATS | Endpoint | Slug example |
|---|---|---|
| Greenhouse | https://boards-api.greenhouse.io/v1/boards/{slug}/jobs?content=true |
gitlab |
| Lever | https://api.lever.co/v0/postings/{slug}?mode=json |
palantir |
| Ashby | https://api.ashbyhq.com/posting-api/job-board/{slug} |
ashby |
The slug is the company's board name, visible in its careers-page URL (boards.greenhouse.io/gitlab, jobs.lever.co/palantir, jobs.ashbyhq.com/ashby).
Normalize them in ~20 lines of Python
import requests
def greenhouse(slug):
r = requests.get(f"https://boards-api.greenhouse.io/v1/boards/{slug}/jobs", timeout=30).json()
return [{"title": j["title"], "location": (j.get("location") or {}).get("name"),
"url": j["absolute_url"], "posted": j.get("updated_at")} for j in r["jobs"]]
def lever(slug):
r = requests.get(f"https://api.lever.co/v0/postings/{slug}", params={"mode": "json"}, timeout=30).json()
return [{"title": j["text"], "location": j["categories"].get("location"),
"url": j["hostedUrl"], "posted": j["createdAt"]} for j in r]
def ashby(slug):
r = requests.get(f"https://api.ashbyhq.com/posting-api/job-board/{slug}", timeout=30).json()
return [{"title": j["title"], "location": j.get("location"),
"url": j["jobUrl"], "posted": j.get("publishedAt")} for j in r["jobs"]]
for fn, slug in [(greenhouse, "gitlab"), (lever, "palantir"), (ashby, "ashby")]:
jobs = fn(slug)
print(slug, len(jobs), jobs[0]["title"])
Add a remote flag by checking the location string for "remote", and store posted as ISO dates (Lever gives epoch milliseconds).
Finding the slug from a domain
Fetch the company's /careers page and look for links to boards.greenhouse.io/, jobs.lever.co/ or jobs.ashbyhq.com/. Many sites embed the board in an iframe or script tag; the slug is in that URL. When there is no match, try the domain name itself as the slug.
When a ready-made tool beats your script
If you track hundreds of companies, you also need Workable, Recruitee and SmartRecruiters, retries, and de-duplication. Disclosure: I built an Apify actor for exactly that: ats-open-roles. Give it company slugs or domains, get normalized open roles back. It is pay-per-result at $0.002 per job, so 1,000 roles cost about $2. If you only need a handful of companies, the script above is the better deal.
Top comments (0)