ATS Job Board API - Greenhouse, Lever, Ashby & Personio avatar

ATS Job Board API - Greenhouse, Lever, Ashby & Personio

Pricing

from $2.00 / 1,000 results

Go to Apify Store
ATS Job Board API - Greenhouse, Lever, Ashby & Personio

ATS Job Board API - Greenhouse, Lever, Ashby & Personio

Give it your own list of companies, get every open role across four applicant-tracking systems in one normalised schema. Uses each vendor's official public job-board API - no login, no proxy, no scraping.

Pricing

from $2.00 / 1,000 results

Rating

0.0

(0)

Developer

Project Desk

Project Desk

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

3 days ago

Last modified

Categories

Share

ATS Job Board API — Greenhouse, Lever, Ashby & Personio

Give it your own list of companies. Get back every open role across four applicant-tracking systems in one schema, deduplicated where a company posted the same role to two of them.

No login. No proxy. No scraping. Each of these vendors publishes a public job-board API so third parties can embed a customer's careers page — this Actor consumes exactly those documented endpoints.


Why this exists

Most job Actors sell you a hosted feed of somebody else's target list. If you want your forty companies polled every morning, that isn't what you're buying.

This is the other shape: you supply the companies, it returns their roles. Useful for recruiters tracking a client's competitors, sales teams reading hiring as a buying signal, job seekers watching a shortlist, and anyone building a niche job board.


Input

One entry per company, as a careers URL or the short ats:token form. Both work, mixed freely:

https://boards.greenhouse.io/gitlab
https://jobs.lever.co/leverdemo
https://jobs.ashbyhq.com/notion
acme.jobs.personio.de
greenhouse:stripe
lever:spotify

Where the token comes from. It is the company's name in its board URL — the gitlab in boards.greenhouse.io/gitlab. If a company's careers page is a JavaScript app that doesn't show its board URL, open a single job posting; the address bar will show the real board.

OptionDefaultWhat it does
boardsThe companies. Required.
includeDescriptiontrueFull job text. Off gives a fast list of titles and links.
deduplicatetrueMerge a role cross-posted to two boards, keeping the fuller copy.
remoteOnlyfalseKeep only remote roles.
titleFilterCase-insensitive substring on the title.
maxJobs0Cap the rows. 0 is no cap. If the cap bites, the log says by how much.
maxConcurrency8Boards fetched at once.

Output

One row per role, the same seventeen fields whatever the source:

FieldNotes
atsgreenhouse, lever, ashby, personio
company, board_token, job_idjob_id is the vendor's own and is stable across runs — the right key for diffing new and closed roles
title, location, all_locationsLocation exactly as the company wrote it, never re-mapped
remoteOne boolean, derived — the four vendors each say it differently
department, team
employment_type, workplace_typeVendor wording preserved rather than normalised into a guess
apply_urlThe public posting on the company's own board
posted_at, updated_atISO 8601 where the board provides it, empty where it doesn't. Never invented
description, description_charsPlain text, HTML stripped. The char count is a cheap way to spot stub postings

Two things worth knowing before you buy

Deduplication is deliberately conservative. It merges a role only when it appears on two different boards. Two roles on the same board that share a title and location are kept as two rows — a company hiring three Support Engineers in London is not a bug to be cleaned up, and an earlier, cleverer version of this merged "AI Engineer, Bangalore" into "Senior AI Engineer, US". Under-merging shows you one extra row; over-merging silently destroys a real vacancy. This errs toward the harmless mistake.

SmartRecruiters and Workable are not supported, on purpose. Both publish a public postings endpoint, and both currently return HTTP 200 with a valid but permanently empty response for every company tested (SmartRecruiters: eight companies, all zero results; Workable: nine accounts, all empty). Rather than ship adapters that always return nothing, they are left out until one demonstrably returns a job.


Coverage

Verified live on 27 August 2026, plain unauthenticated requests:

ATSEndpointTest boardResult
Greenhouseboards-api.greenhouse.io/v1/boards/{token}/jobs?content=truegitlab218 jobs
Leverapi.lever.co/v0/postings/{token}?mode=jsonleverdemo384 jobs
Ashbyapi.ashbyhq.com/posting-api/job-board/{token}notion135 jobs
Personio{token}.jobs.personio.de/xmldemoXML, live

741 rows in one run across the four, 712 of them carrying a real description.

Ashby roles marked isListed: false are skipped — the company has taken those off its public board, and republishing them would be wrong.


Run it locally

No Apify account, no Docker:

python tools/try_local.py greenhouse:gitlab lever:leverdemo https://jobs.ashbyhq.com/notion

Writes tools/out/local-run.json and prints a summary. Same code path as the Actor — only the Apify wiring is replaced.

Tests, stdlib only:

python tests/test_ats.py

79 assertions, including a regression block guarding the dedupe behaviour described above, and fixtures trimmed from real vendor responses so a shape change surfaces here rather than in production.


Pricing

Pay per result. You are charged per job row pushed, and nothing else — no platform fee, no charge for a board that returns empty. Turning includeDescription off does not reduce the row count and so does not reduce the price; it just makes runs faster and the output smaller.