Career Site Job Feed - Live Workday, Greenhouse & 8 More ATS avatar

Career Site Job Feed - Live Workday, Greenhouse & 8 More ATS

Pricing

from $2.00 / 1,000 job results

Go to Apify Store
Career Site Job Feed - Live Workday, Greenhouse & 8 More ATS

Career Site Job Feed - Live Workday, Greenhouse & 8 More ATS

Read job postings live from the employer's own applicant tracking system at run time — no stored index, so a row cannot outlive the posting. 27,681 company boards across 10 platforms, one schema.

Pricing

from $2.00 / 1,000 job results

Rating

0.0

(0)

Developer

Sulle H

Sulle H

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

9 hours ago

Last modified

Share

Career Site Job Feed — Workday, Greenhouse & 27,000+ ATS Boards

Search live job postings straight from 27,681 company career sites in a single feed — 1.36 million openings across nine applicant tracking systems.

Most job APIs resell a stale aggregator index. This one reads each employer's own ATS at run time, so a row means the job is on that company's careers page right now, with a direct apply link rather than a redirect through a job board.

PlatformBoards coveredLive postings
Workday2,658595,820
SmartRecruiters4,334363,544
Greenhouse5,578179,052
Workable1,71077,339
Lever1,91763,622
Ashby1,59632,007
Breezy HR2,80047,301
Personio5,17241,685
Rippling1,29818,647
Pinpoint61818,235
Total27,6811,437,252

No login, no cookies, no proxies, no API keys. One normalized schema across all ten platforms.

Read at run time, not served from an index

There are two ways to build a job API, and the difference matters more than coverage counts do.

The aggregator way. Crawl thousands of career sites on a schedule, store the results, serve them from a database, enrich them. You get scale — the largest of these covers around 200,000 career sites — and extras like company metadata that only make sense once the data is warehoused. What you also get is a gap between the crawl and your query: a posting filled last Tuesday is still in the index until the next crawl notices, and "active in the last six months" is doing a lot of work in that sentence.

This Actor's way. When you run it, it calls each employer's own applicant tracking system and returns what that board answers. There is no stored copy. A row exists because the company's careers page listed it seconds ago, and scrapedAt on every row is the timestamp of that call.

Neither is better in the abstract. If you want the widest possible index and do not mind that some rows are stale, use an aggregator. If a wrong row costs you — a candidate applying to a filled role, a lead list of companies that stopped hiring, an alert that fires on something already gone — read live.

You can check this rather than believe it. Take any row, open its applyUrl, and the posting is there. Run again a week later against the same company and the roles that closed are simply absent, because nothing is holding a copy.

Freshness, measured rather than promised

Every job API claims it has no stale listings. Here is what is actually in these sources, sampled across the registry:

PlatformPosted ≤ 90 daysOlder than a year
Ashby83%2%
Greenhouse63%15%
Workable52%5%
SmartRecruiters (largest boards)50%50%

Some employers — staffing agencies especially — leave requisitions open for years. Rather than pretend otherwise, this Actor defaults to postings from the last 90 days. A default run comes back with a median posting age of 6 days.

  • Want everything, including long-open roles? Set postedWithinDays to a large number such as 3650.
  • Want only this week? Set it to 7.
  • Postings with no publication date are always kept, because their age is unknown rather than old. That is most Workday rows — see the note below.

What a row looks like

{
"provider": "smartrecruiters",
"companySlug": "sgs",
"company": "SGS",
"jobId": "744000143984409",
"title": "Assistant Consumer Safety Engineer (Electrical & Electronic)",
"location": "Senai, my",
"department": "Laboratory & Testing",
"employmentType": "Full-time",
"remote": false,
"postedAt": "2026-08-18T05:52:19.533Z",
"applyUrl": "https://jobs.smartrecruiters.com/sgs/744000143984409",
"salary": null,
"descriptionText": "...",
"scrapedAt": "2026-08-18T10:14:02.881Z"
}
FieldDescription
company / companySlugCompany name and its board identifier. Pass companySlug back in companies to watch one employer.
providerWhich ATS the posting came from
jobIdStable per-posting id — use it to dedupe across runs
titleJob title
locationLocation string as the employer published it
departmentDepartment or team, where the ATS exposes it
employmentTypeFull-time, contract, and so on, where exposed
remoteRemote flag, where the ATS exposes it
postedAt / updatedAtISO timestamps, or null when the source gives no date
applyUrlDirect application link on the employer's own site
salaryPay range as the employer wrote it. Only Breezy and Ashby publish this on their listing endpoints; null elsewhere.
descriptionTextFull description as plain text, when includeDescription is on
scrapedAtWhen this row was read, ISO 8601

Input

{
"keywords": ["engineer", "developer"],
"excludeKeywords": ["senior", "staff"],
"locations": ["berlin", "remote"],
"postedWithinDays": 30,
"maxBoards": 500,
"maxJobs": 2000,
"includeDescription": false
}
OptionWhat it does
keywordsKeep titles containing any of these (case-insensitive). Empty = every job.
excludeKeywordsDrop titles containing any of these.
locationsKeep postings whose location matches any entry.
remoteOnlyKeep only postings flagged remote by the ATS or with a remote-looking location.
postedWithinDaysFreshness window. Defaults to 90.
companiesRestrict to specific board slugs. Empty = the whole 27,681-board registry.
providersRestrict to greenhouse, personio, smartrecruiters, breezy, workday, lever, workable, ashby, rippling, pinpoint.
maxBoardsHow many boards to scan, largest employers first.
maxJobsCap on returned rows, so a run costs what you expect. Defaults to 1,000 — clearing the box falls back to that, so type a large number (e.g. 500000) to sweep everything.
includeDescriptionTurn off for a much faster, lighter run.
concurrencyParallel requests. Higher is faster but likelier to hit ATS rate limits.

What people use it for

A job board or newsletter. Run it on a schedule with your niche keywords and push straight into your own database. Every row carries an apply link to the employer, so your users never bounce through a third party.

Recruiting and sourcing. Ask which companies are hiring a given role right now: keywords: ["site reliability"], postedWithinDays: 14.

Market and competitive research. Headcount signals straight from the source. Restrict to one employer with companies: ["wd5:nvidia:nvidiaexternalcareersite"] and watch what they open.

Lead generation. A company posting five sales roles is a company with a budget. Filter on titles, keep company and applyUrl, and hand the list to your CRM.

Sending results somewhere

The dataset is standard Apify output, so the platform's own integrations do the delivery — Slack, Zapier, Make, a webhook, Google Sheets, or a direct API pull:

https://api.apify.com/v2/datasets/<datasetId>/items?clean=true&format=json

Pair it with an Apify Schedule to get a recurring feed. If you only want postings you have not seen before, use the companion Actor New Job Alerts, which remembers what it already delivered.

A note on Workday

Workday is where most large enterprises post, and it is the biggest single source here — Accenture, Walmart, CVS Health, Lowe's. Its public listing endpoint carries less than the others: Workday rows carry company, title, location, employment type, requisition id and apply link, and no department or description. Those live behind a per-posting request that a per-result price cannot cover.

Workday also reports posting age as text ("Posted Today", "Posted 30+ Days Ago"), so postedAt is exact when the age is exact and null when it is not — a missing date rather than an invented one.

Performance

A 300-board scan returns 3,628 engineer postings in 8 seconds with zero board failures, measured on Apify. Boards are scanned largest-first, so a capped run returns the most jobs per credit.

Raise maxBoards for wider coverage — the full registry holds 1,437,252 live postings across 27,681 boards.

Which fields each platform actually gives you

Ten applicant tracking systems, one schema — but they do not all publish the same things. These are measured from real runs, not from vendor documentation:

FieldWorkdaySmartRecruitersGreenhouseWorkableLeverAshbyBreezyPersonioPinpointRippling
title, company, locationyesyesyesyesyesyesyesyesyesyes
applyUrlyesyesyesyesyesyesyesyesyesyes
postedAtpartialyesyesyesyesyesyesnonono
departmentnoyesyesyesyesyesyesyesyesyes
employmentTypeyesyesnoyesyesyesyesyesyesno
remote flagnoyesnoyesinferredyesyesinferredyesinferred
descriptionTextnonoyesyesyesyesnonoyesno
salarynononononoyesyesno37%no

Two consequences worth knowing before you build on this:

  • includeDescription does nothing for Workday, SmartRecruiters or Breezy rows. Their listing endpoints carry no description, and fetching one per posting would cost a request per row. Those rows return null however the option is set.
  • Workday's postedAt is partial by design. It reports age as prose — "Posted Today", "Posted 30+ Days Ago" — so an exact age becomes a timestamp and a vague one becomes null, rather than a made-up date. Date filters keep rows with no date rather than dropping them.

Live read versus an aggregator index

Most job APIs answer from a database they refreshed at some earlier point. This one calls each employer's ATS while your run is happening. The trade-off is honest in both directions:

This ActorAggregator index
Freshnessas of this secondas of their last crawl
Ghost jobsgone the moment the employer closes itlinger until the next crawl
Apply linkthe employer's own URLoften a redirect
Speedseconds to minutes, bounded by the ATSinstant
Coverageemployers whose board we knowwhatever they indexed

If you need a million rows in one second, use an index. If you need rows that are true right now and apply links that go straight to the employer, read live.

Recipes

A daily job board feed. Schedule a run with postedWithinDays: 1 and your keywords, then push the dataset into your database through Apify integrations. Deduplicate on provider:companySlug:jobId, which is stable across runs.

Track one company's hiring over time. Put its slug in companies, raise maxJobsPerCompany, and run weekly. Diffing jobId between runs shows what opened and what closed.

Find employers on a given platform. Set providers: ["workday"] and maxJobs high. The companySlug column becomes a list of companies using that ATS — useful for technographic segmentation as well as recruiting.

Watch a whole sector. Combine keywords with locations, raise maxBoards, and lower maxJobsPerCompany so no single large employer dominates the result.

Troubleshooting

"I got fewer rows than maxJobs." Filters are applied after fetching, so a narrow keyword or a short postedWithinDays can exhaust the boards before the cap. Raise maxBoards, widen the window, or loosen keywords.

"One company dominates my results." Lower maxJobsPerCompany. It defaults to 25 for exactly this reason.

"A board I expect is missing." It may not be in the registry, or it may have closed. The registry is re-validated monthly; boards that stop answering are dropped.

"Some rows have no description." See the field table above — five of the ten platforms do not publish descriptions on their listing endpoints.

If you only need one ATS

This Actor is built for breadth — it does not ask you which applicant tracking system a company uses, because the registry already knows. When you only care about one platform, a narrower Actor is cheaper to reason about and its input schema has fewer knobs:

ActorCoverage
Workday Jobs Scraper2,658 Workday boards — paste a careers URL
SmartRecruiters Jobs Scraper4,334 SmartRecruiters boards
Breezy HR Jobs Scraper2,800 Breezy boards, with pay ranges
Workable Jobs Scraper1,710 Workable boards, with full descriptions
Greenhouse Jobs ScraperAny Greenhouse board by slug or URL, with full descriptions

All of them emit the same row shape as this Actor, so datasets from any combination can be unioned without a mapping layer.

Use it as an API

Most people who rely on this Actor never open the Apify console after the first run — they call it from their own code and read the rows straight back. One request in, job rows out, no polling and no dataset id to chase:

curl -X POST "https://api.apify.com/v2/acts/starbright_overlap~ats-job-feed/run-sync-get-dataset-items?token=YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{"keywords": ["engineer"], "locations": ["berlin"], "maxJobs": 200}'
import requests
rows = requests.post(
"https://api.apify.com/v2/acts/starbright_overlap~ats-job-feed/run-sync-get-dataset-items",
params={"token": "YOUR_TOKEN"},
json={"keywords": ["engineer"], "locations": ["berlin"], "maxJobs": 200},
timeout=300,
).json()
for r in rows:
print(r["company"], "—", r["title"], "—", r["applyUrl"])
const rows = await (await fetch(
'https://api.apify.com/v2/acts/starbright_overlap~ats-job-feed/run-sync-get-dataset-items?token=YOUR_TOKEN',
{ method: 'POST', headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({"keywords": ["engineer"], "locations": ["berlin"], "maxJobs": 200}) },
)).json();

Your token is at Settings → Integrations in the Apify console. Keep maxJobs set to what you actually need — it is the cap that decides what the call costs.

Running it on a schedule instead

If you want the rows to arrive without asking, add a Schedule from the Actor page (Actions → Schedule) and point a webhook at your endpoint. A daily schedule plus the postedWithinDays filter is the usual setup for a job board or an alerting pipeline.

Pricing

Pay per result. You are charged per job row delivered; boards that fail or return nothing cost you nothing. Platform usage is included rather than billed on top, so the per-result price is the whole price.

How the registry stays current

Boards die and companies migrate between ATS vendors constantly. The bundled registry is re-validated every month — dead boards are dropped and posting counts refreshed — so runs do not waste time on employers that have moved on.

Notes

  • The registry ships inside the Actor, so there is no setup and no external lookup at run time.
  • Dead or rate-limited boards are skipped without aborting the run; the details land in a FAILED_BOARDS record in the key-value store.
  • Set includeDescription: false when you only need titles and links — it is several times faster.
  • Job ids are stable per posting, so provider:companySlug:jobId makes a reliable dedupe key.

Frequently asked

Is there a free Greenhouse / Workday / Lever jobs API? The underlying ATS endpoints are public and unauthenticated — anyone can call them. What is hard is knowing which companies exist on which platform, which is what the 27,681-board registry here is. If you only need one employer you already know, call the ATS directly; this Actor is for searching across all of them at once.

How is this different from a job aggregator API? Aggregators index job boards and resell that index, so postings arrive second-hand and often after the employer already filled the role. This reads each employer's ATS during the run. The apply link points at the company, not at a middleman.

Can I get every job from one specific company? Yes. Put its board slug in companies and raise maxJobs. Slugs come back on every row as companySlug — for example databricks on Greenhouse, or wd5:nvidia:nvidiaexternalcareersite on Workday.

Which ATS platforms are covered? Workday, Greenhouse, SmartRecruiters, Workable, Lever, Ashby, Breezy, Personio, Rippling and Pinpoint HR. Restrict with providers if you only want some.

Do I get salary data? Sometimes, and the salary field says exactly when. Breezy and Ashby publish a pay range on their listing endpoints — "$70,000 – $85,000 / year", "$211.4K – $290.6K • Offers Equity" — and those come through as written. The other five platforms expose no salary field at all, so salary is null there rather than invented. Anything they mention inside the job text still turns up in descriptionText when includeDescription is on.

How fresh are the postings? A default run has a median posting age of 6 days, because postedWithinDays defaults to 90. The measured age distribution per platform is in the freshness table above.

Can I run it on a schedule? Yes — add an Apify Schedule. If you want only postings you have not already seen, use the New Job Alerts Actor instead; it keeps a per-feed memory and returns just the new ones.

What happens if a company's board is down? That board is skipped and the run continues. Failures are collected in a FAILED_BOARDS record so you can see exactly which ones and why.

Why do some rows have no department or description? Different ATS platforms expose different fields. Workday's list endpoint, in particular, has no department, employment type or description. Rather than filling gaps with guesses, missing values come back as null.


Listed on AllMCPs — this Actor is also reachable as a remote MCP server at https://mcp.apify.com/?tools=starbright_overlap/ats-job-feed.

AllMCPs