ATS Jobs API: Greenhouse, Lever, Workday, SmartRecruiters +7 avatar

ATS Jobs API: Greenhouse, Lever, Workday, SmartRecruiters +7

Pricing

from $1.80 / 1,000 unique job saveds

Go to Apify Store
ATS Jobs API: Greenhouse, Lever, Workday, SmartRecruiters +7

ATS Jobs API: Greenhouse, Lever, Workday, SmartRecruiters +7

Job listings API for 11 ATS career sites: Greenhouse, Lever, Ashby, Workday, SmartRecruiters, Workable, Personio, Recruitee, Teamtailor, BambooHR, Rippling.

Pricing

from $1.80 / 1,000 unique job saveds

Rating

0.0

(0)

Developer

Christian Barbosa

Christian Barbosa

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

2 hours ago

Last modified

Share

ATS Jobs API: Greenhouse, Lever, Workday, SmartRecruiters and 7 more

ATS Jobs Scraper returns every open job, in one normalized row per job, straight from company career sites hosted on 11 applicant tracking systems (ATS): Greenhouse, Lever, Ashby, Workday, SmartRecruiters, Workable, Personio, Recruitee, Teamtailor, BambooHR and Rippling. Use it as a Greenhouse jobs API, a Lever jobs scraper, a Workday jobs scraper, a SmartRecruiters or Workable jobs API, or a Personio, Recruitee, Teamtailor, BambooHR or Rippling job board scraper: paste career page URLs, board URLs or board names and the ATS is detected automatically. Every job comes in one normalized schema with salary, remote flag, department, location, country, posted date and the full description. For scheduled monitoring, each run returns only new jobs since the last run and, optionally, the jobs that closed since then. You pay only per unique job saved. Companies with no jobs, filtered-out jobs, duplicates, invalid inputs and errors are free.

Why this ATS jobs scraper

  • Data straight from the source. The Actor reads the official public job board APIs of each ATS. No browser, no HTML guessing, no aggregator in the middle, so jobs appear as soon as the company publishes them.
  • New and closed jobs since your last run. Monitoring mode returns only jobs not delivered before. With Report closed jobs, every job that was filled, expired or removed from the board is reported once, so your job board, CRM or alert list never keeps dead listings.
  • Strict "posted since" filter. Keep only jobs published in the last 24 hours, 7 days or since a date. The filter is checked again on every job right before it is saved, so an old job is never delivered or charged.
  • Complete boards. Workday stops every search at 2,000 results. This Actor splits large Workday boards by job category and location (tested: 2,679 of 2,679 jobs on one board).
  • Accurate salaries. Structured pay ranges from Lever, Ashby and Greenhouse, and ranges written in the description for the rest. Every salary says where it came from (salarySource).
  • No duplicates. Each job has a stable key, jobKey (ats:board:jobId), and is saved once per run even if two inputs point to the same board.
  • Clear status per company. Every input ends with an explicit status in the RUN_SUMMARY record. If more than 20% of companies fail, the run is marked as failed so you notice.
  • Safe on long runs. Progress is saved continuously. A platform restart never duplicates rows or charges twice.

How to use it

  1. In Companies, add one company per line. Any of these forms works:
    • Board URL: https://boards.greenhouse.io/stripe, https://jobs.lever.co/spotify, https://jobs.ashbyhq.com/ramp, https://nvidia.wd5.myworkdayjobs.com/NVIDIAExternalCareerSite, https://jobs.smartrecruiters.com/BoschGroup, https://apply.workable.com/huggingface, https://tado.jobs.personio.de, https://bunq.recruitee.com, https://career.teamtailor.com, https://hubstaff.bamboohr.com/careers, https://ats.rippling.com/rippling/jobs
    • Company career page that links to one of these systems: https://www.figma.com/careers/
    • Explicit form: greenhouse:stripe, lever:spotify, ashby:ramp, lever-eu:company (Lever EU), smartrecruiters:BoschGroup, workable:huggingface, personio:tado, recruitee:bunq, teamtailor:career, bamboohr:hubstaff, rippling:rippling. For a Teamtailor career site on its own domain, use teamtailor:https://jobs.example.com.
    • Bare board name: stripe (looked up on Greenhouse, Lever and Ashby only)
  2. Optional filters: Keywords, Exclude keywords, Locations, Departments, Remote jobs only, Employment types, Seniority levels, Visa sponsorship stated and Posted since (2026-10-01, 24 hours, 7 days, 2 weeks).
  3. Optional limits: Max jobs per company (newest first) and Max jobs in total.
  4. For recurring runs, enable Only new jobs since last run and, if you need it, Report closed jobs.
  5. Run the Actor and download the results as JSON, CSV or Excel, or read them through the API.

Example input for a daily engineering-jobs monitor:

{
"companies": ["https://boards.greenhouse.io/stripe", "lever:spotify", "ashby:ramp"],
"keywords": ["engineer"],
"postedSince": "7 days",
"onlyNewSinceLastRun": true,
"reportClosedJobs": true,
"monitoringStoreName": "engineering-monitor",
"descriptionFormat": "text"
}

Workday always needs the full career site URL, because Workday board names cannot be looked up.

Supported ATS and public source

ATSAccepted inputPublic source usedDescription
Greenhouseboards.greenhouse.io/{company}Job Board APIIncluded
Leverjobs.lever.co/{company}Postings API (global and EU)Included
Ashbyjobs.ashbyhq.com/{company}Job Board APIIncluded
WorkdayFull career site URLCareer site JSONOne request per job
SmartRecruitersjobs.smartrecruiters.com/{Company}Posting APIOne request per job
Workableapply.workable.com/{company}Careers widget APIIncluded
Personio{company}.jobs.personio.deXML job feedIncluded
Recruitee{company}.recruitee.comCareers APIIncluded
Teamtailor{company}.teamtailor.comCareer site RSS feedIncluded
BambooHR{company}.bamboohr.com/careersCareers JSONOne request per job
Ripplingats.rippling.com/{company}/jobsJob board APIOne request per job

All sources are public job board endpoints that need no login or key. Every ATS returns the same fields; a field stays empty when that ATS does not publish it.

Monitoring new and closed jobs

Only new jobs since last run keeps a named key-value store (default name ats-jobs-monitor) that remembers, per company, the jobs already delivered. Later runs skip them, so you are charged only for new jobs. The first monitored run of a company returns all matching jobs.

Report closed jobs compares the full list of jobs on each board with the jobs delivered in earlier runs. A job that is no longer listed is saved once as a row with recordType: "closed", with its title, location, job link, firstSeenAt and closedDetectedAt. Safeguards against false closures:

  • Two-run confirmation. A job is reported only when it is missing from two complete listings in a row. A temporary ATS error never produces a closure. In practice, a closure appears one scheduled run after the job disappears.
  • Closures are checked only when the complete job list of the board was read in that run. A failed, partial or truncated listing is skipped and checked again on the next run.
  • A job is reported as closed only once, and it is never delivered or charged again afterwards, even if it reappears on the board.
  • Filters do not create closures: a job that still exists but no longer matches your filters is not reported.

Use a different Monitoring store name for each independent monitor (for example one per client). To start over, delete the store in Storage. Closed jobs can be detected only for jobs delivered while Report closed jobs was enabled.

Integrations: schedules, API, webhooks, Sheets, Zapier, Make and AI agents

Schedules. Save your input as a task, then open Schedules in Apify Console and run it hourly or daily. With monitoring enabled, each scheduled run returns only what changed.

API. Run the Actor and get the results in one call:

curl -X POST "https://api.apify.com/v2/acts/ocius-data~ats-jobs-scraper/run-sync-get-dataset-items?token=YOUR_API_TOKEN&format=json" \
-H "Content-Type: application/json" \
-d '{"companies": ["ashby:ramp"], "postedSince": "24 hours"}'

Python, with the official apify-client package:

from apify_client import ApifyClient
client = ApifyClient("YOUR_API_TOKEN")
run = client.actor("ocius-data/ats-jobs-scraper").call(run_input={"companies": ["lever:spotify"], "onlyNewSinceLastRun": True})
for job in client.dataset(run["defaultDatasetId"]).iterate_items():
print(job["recordType"], job["title"], job["applyUrl"])

The results of the latest run are always at https://api.apify.com/v2/acts/ocius-data~ats-jobs-scraper/runs/last/dataset/items?token=YOUR_API_TOKEN&status=SUCCEEDED (add &format=csv for CSV).

Webhooks. In the Actor or task, open Integrations, add a webhook for the event ACTOR.RUN.SUCCEEDED and point it at your endpoint. The payload contains resource.defaultDatasetId, which you use to download the new and closed jobs.

Google Sheets. Add the Google Sheets integration in the Integrations tab of your task, or download the dataset as CSV and import it. Use jobKey as the unique column to update rows, and recordType to mark closed jobs.

Zapier, Make and n8n. Use the official Apify app or node. Trigger: "Actor run finished". Action: "Get dataset items". Then send each new job to Slack, email, Airtable or your ATS.

MCP and AI agents. The Actor runs with limited permissions, so it is available through the Apify MCP server (https://mcp.apify.com). Add ocius-data/ats-jobs-scraper to the server's Actor list and an AI agent can call it with plain inputs such as {"companies": ["stripe"], "keywords": ["data"]}.

Pricing and cost calculator

Pay per event. There is no start fee. The price of the job event is lower on higher Apify plans:

Your Apify planPrice per jobPer 1,000 jobs
FreeUSD 0.003USD 3.00
BronzeUSD 0.0025USD 2.50
SilverUSD 0.002USD 2.00
Gold, Platinum and DiamondUSD 0.0018USD 1.80
EventPriceWhen it is charged
jobSee the table aboveOne unique open job saved to the dataset.
job-closedUSD 0.003 per closed jobOne closed job reported with Report closed jobs. Never charged otherwise.

What one price covers. One run reads all 11 supported ATSs together, returns the same normalized fields for all of them, and includes "only new jobs" monitoring and closed-job detection. Single-ATS tools can cost less per job but cover one system each, and curated career-site feeds typically cost about twice as much per job.

Never charged: companies with no jobs, jobs removed by your filters, duplicates, jobs already delivered in monitoring mode, invalid inputs and errors. Your maximum cost per run is respected for both events together: the Actor saves only what it can charge and stops as soon as the limit is reached. Closed jobs that did not fit are kept and reported on the next run.

Examples at the Free plan price (USD 0.003 per job). On Bronze, Silver and higher plans the job part costs less.

ScenarioEventsCost on the Free plan
One company with 200 open jobs200 jobUSD 0.60
20 companies, engineering jobs only (about 15 each)300 jobUSD 0.90
50 companies, full boards (about 100 each)5,000 jobUSD 15.00
Daily monitor of 100 companies after the first run: about 150 new and 120 closed jobs per day150 job + 120 job-closedUSD 0.81 per day, about USD 24 per month
Same monitor without closed jobs150 jobUSD 0.45 per day, about USD 14 per month

To keep costs down, use filters, Posted since and Max jobs per company: filtered-out jobs are free. Defects: if a run delivers wrong or incomplete jobs because of a defect in the Actor, open an issue with the run ID. Defects are fixed with priority, usually within 72 hours.

Output example and field dictionary

{
"recordType": "job",
"jobKey": "ashby:ramp:318e7138-151e-4ed2-8b85-a017d234ef12",
"company": "ramp",
"ats": "ashby",
"boardToken": "ramp",
"jobId": "318e7138-151e-4ed2-8b85-a017d234ef12",
"title": "Manager, Mid-Market Solutions Consulting",
"department": "Sales",
"team": "Solutions Consulting",
"location": "New York, NY (HQ)",
"countryCode": "US",
"workplaceType": "HYBRID",
"isRemote": true,
"employmentType": "FULL_TIME",
"salaryMin": 195000,
"salaryMax": 298000,
"salaryCurrency": "USD",
"salaryPeriod": "YEAR",
"salarySource": "ats",
"applyUrl": "https://jobs.ashbyhq.com/ramp/318e7138-151e-4ed2-8b85-a017d234ef12/application",
"postedAt": "2026-10-31T19:31:59.653Z",
"input": "https://jobs.ashbyhq.com/ramp",
"sourceUrl": "https://api.ashbyhq.com/posting-api/job-board/ramp?includeCompensation=true",
"scrapedAt": "2026-11-01T19:36:53.268Z"
}
FieldMeaningWhen it is null
recordTypejob (open job) or closed (job delivered earlier and no longer listed).Never
jobKeyStable unique key ats:boardToken:jobId. Use it to deduplicate and update rows.Never
companyCompany name published by the ATS. Lever, Ashby, Workday, BambooHR and some Rippling boards do not publish it, so the board name is used.Never
ats, boardToken, jobIdATS (greenhouse, lever, ashby, workday, smartrecruiters, workable, personio, recruitee, teamtailor, bamboohr, rippling), board identifier (Workday: tenant/site; Teamtailor custom domain: the host name) and job identifier.Never
requisitionIdInternal requisition number.Lever and Ashby; Greenhouse when not published
titleJob title.Never
department, teamBroad group and specific team.When the company does not set them
location, locationsPrimary location and all locations, as written by the company.location when none is published
countryCodeISO 3166-1 alpha-2 country of the primary location.When the location names no country
workplaceType, isRemoteREMOTE, HYBRID or ONSITE; isRemote is true when the job can be done fully remote from at least one location.workplaceType when not published
employmentType, employmentTypeRawFULL_TIME, PART_TIME, CONTRACT, TEMPORARY or INTERNSHIP, and the value as published.When not published or not one of these
seniorityLevel inferred from the title: INTERN, ENTRY, MID, SENIOR, PRINCIPAL, DIRECTOR or EXECUTIVE. Rule-based and free, so you can filter or group jobs without an AI step.When the title has no clear level (for example "Product Designer")
yearsExperienceMinMinimum years of experience requested in the description (for example 5 for "5+ years of experience").When the description does not state it
visaSponsorshiptrue when the description states that visa sponsorship is offered, false when it states that it is not.When the description does not mention sponsorship (most jobs)
salaryMin, salaryMax, salaryCurrency, salaryPeriodPay range, ISO 4217 currency and period (YEAR, MONTH, WEEK, DAY, HOUR).When no salary is published
salarySource, salaryTextats (structured field) or description (job text), and the salary as written.When no salary is found
descriptionText, descriptionHtmlFull description as plain text and as HTML.When removed with Description format; not present in closed rows
jobUrl, applyUrlPublic job page and application page.jobUrl when the ATS gives none
postedAt, updatedAtFirst publication and last update, ISO 8601 UTC.When the ATS does not publish them
firstSeenAt, closedDetectedAtClosed rows only: when the job was first delivered and when the closure was detected.Not present in open-job rows
input, sourceUrl, scrapedAtInput line, public ATS endpoint and collection time (UTC).Never

The output tab has four views: Overview, New and closed, Salaries and All fields.

Statuses and errors

Statuses are in the RUN_SUMMARY record, never in the dataset.

StatusMeaningChargedWhat to do
OKJobs were saved.Per jobNothing
NO_NEW_JOBSMonitoring: every matching job was delivered before. Closed jobs may still be reported.Only closed jobsNothing
NO_MATCHESThe board has jobs, but none matched your filters.NoRelax the filters.
NO_JOBSThe board exists and has no open jobs.NoNothing
DUPLICATE_INPUTSame board as an earlier line.NoRemove the line.
NOT_PROCESSEDYour maximum cost, Max jobs in total or the timeout was reached first.NoRaise the limit or split the list.
INVALID_INPUTThe line is not a valid URL or board name.NoCorrect the line.
NOT_FOUNDThe ATS says this board does not exist.NoCheck the spelling.
ATS_NOT_DETECTEDNo supported ATS was found for this name or page.NoPaste the board URL.
BLOCKEDThe ATS kept rate-limiting after all retries.NoRun again later or set a proxy.
ERRORUnexpected response from the ATS.NoOpen an issue with the run ID.

Per company, RUN_SUMMARY also shows jobs on the board, jobs delivered, closedJobs, closedJobsPending (missing once, waiting for confirmation) and the reason when fewer jobs were delivered. At run level it shows field completeness and the reconciliation between rows saved and events charged for both events.

Known limits

  • Supported systems: Greenhouse, Lever (global and EU), Ashby, public Workday career sites, SmartRecruiters, Workable, Personio, Recruitee, Teamtailor, BambooHR and Rippling. iCIMS, SAP SuccessFactors and Oracle Taleo are not supported, because they do not offer a public job board endpoint that works the same way for every company.
  • Bare names are looked up only on Greenhouse, Lever and Ashby. For the other systems, use the board URL or the ats:name form.
  • SmartRecruiters answers an unknown company with an empty list, so a misspelled identifier is reported as NOT_FOUND. Some identifiers are case-sensitive: copy it from jobs.smartrecruiters.com/{identifier}.
  • Teamtailor feeds do not include the employment type. Feeds with 100 jobs or more are not used for closed-job detection, because the feed size limit is not documented.
  • Career page detection works when the page links to the ATS in its HTML. For pages built entirely with JavaScript, paste the board URL. The Actor never guesses a board from the domain name.
  • Bare names may match an inactive board on another ATS. When a name exists on several systems, the board with the most jobs is used. Use URLs for full control.
  • Workday, SmartRecruiters, BambooHR and Rippling need one request per job for the description: about 2 to 3 minutes per 1,000 jobs.
  • Posted since drops jobs that have no publication date, because they cannot be verified.
  • Closed jobs are reported after two complete listings in a row without the job, so the first closure appears on the third monitored run at the earliest. Each monitor remembers up to 20,000 jobs per company and keeps closed-job details for the 5,000 most recent; older jobs that close are dropped without a row and without charge.
  • Closed rows carry the job page in both jobUrl and applyUrl, because the application page no longer exists.
  • Salaries in text are read conservatively; unusual formats are left empty rather than guessed.

FAQ

Is it legal? The Actor reads job postings that companies publish on public job boards through the ATS public APIs. No login is used and no personal data about candidates or recruiters is collected.

How do I get only jobs posted in the last 24 hours? Set Posted since to 24 hours. Combine it with Only new jobs since last run for an hourly or daily feed.

How do I detect expired or filled jobs? Enable Only new jobs since last run and Report closed jobs, and schedule the task. Rows with recordType: "closed" are the jobs removed since the previous run.

Why is department empty for some jobs? The company did not assign one in its ATS.

Is this an alternative to other Greenhouse or Lever job APIs? Yes. It covers 11 ATSs with one schema, detects closed jobs without a separate Actor, and charges per job instead of per run.

Do you offer volume pricing? For more than 1 million rows per month, open an issue on the Actor page to discuss a volume price.

Built to the same standard: a status for every input in RUN_SUMMARY, actionable error messages and list-based inputs, so they chain well in one workflow:

Changelog

  • November 2026 Seven new ATSs in the same Actor and schema: SmartRecruiters, Workable, Personio, Recruitee, Teamtailor, BambooHR and Rippling (URL, ats:name form and career page detection). Country fix: France and the United Kingdom now return FR and GB.
  • November 2026 New fields seniority, yearsExperienceMin and visaSponsorship, inferred from the title and description at no extra cost, and new filters Seniority levels and Visa sponsorship stated.
  • 0.2 (November 2026) Closed-job detection (recordType: "closed", event job-closed) with two-run confirmation against false closures; recordType and jobKey fields; "New and closed" view; the Posted since filter is documented as re-checked before saving.
  • 0.1 (November 2026) First version: Greenhouse, Lever, Ashby and Workday; automatic ATS detection; normalized schema; structured and text salaries; Workday 2,000-result cap bypass; monitoring mode; per-company statuses and run summary.

Open an issue on the Actor page. Issues are answered within one business day. Need jobs from aggregators as well? Google Jobs Scraper by the same publisher returns listings from LinkedIn, Indeed and other job boards through Google Jobs, with the same monitoring mode.