Greenhouse, Lever, Ashby & Workday Jobs API — 8 ATS, $0.60/1K
Pricing
from $0.60 / 1,000 results
Greenhouse, Lever, Ashby & Workday Jobs API — 8 ATS, $0.60/1K
Job postings from 8 ATS — Greenhouse, Lever, Ashby, Workday, Eightfold, Workable, SmartRecruiters, Recruitee — in one schema. Salaries annualized across currencies and languages. Every run reports per-source health, so a broken ATS is visible instead of silently missing. No personal data.
Pricing
from $0.60 / 1,000 results
Rating
0.0
(0)
Developer
Juan Carlos Gutiérrez Huérfano
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
16 days ago
Last modified
Categories
Share
Job Postings Scraper — Greenhouse, Lever, Ashby, Workday, Eightfold, Workable, SmartRecruiters, Recruitee
Pulls open roles straight from companies' own applicant tracking systems and returns one clean schema across all eight, with salary bands parsed into comparable annual figures and an eligibility flag for Latin America.
No personal data is collected or emitted — job postings only.
Supported sources
| ATS | Board URL | Board entry |
|---|---|---|
| Greenhouse | boards.greenhouse.io/stripe | greenhouse:stripe |
| Lever | jobs.lever.co/leverdemo | lever:leverdemo |
| Ashby | jobs.ashbyhq.com/ramp | ashby:ramp |
| Workable | apply.workable.com/hospitable | workable:hospitable |
| SmartRecruiters | jobs.smartrecruiters.com/Acme | smartrecruiters:Acme |
| Recruitee | tether.recruitee.com | recruitee:tether |
| Workday | nvidia.wd5.myworkdayjobs.com/en-US/NVIDIAExternalCareerSite | paste the URL |
| Eightfold | mercadolibre.eightfold.ai/careers | eightfold:mercadolibre/mercadolibre.com |
Why this exists
Every ATS already publishes its job board as a public JSON endpoint. The hard part was never fetching it; it's that each one names things differently, buries compensation in free prose, and describes location in a dozen incompatible ways. Existing scrapers hand you the raw payload and leave the normalization to you.
This one does the normalization:
-
Salary parsed and annualized. Structured fields when the ATS provides them, otherwise parsed from the description — English, Spanish and Portuguese, multi-currency, with
annualizedMin/annualizedMaxso an hourly US rate and a monthly Colombian salary sort in the same column. Every band carries the exactrawTextit came from, and aconfidenceofstructuredorparsed, so you can audit or discard. -
Work mode classified as
remote/hybrid/onsite/unknown— reading the title and body, not just the location string. "Hybrid remote" resolves to hybrid, and a named city with no remote signal resolves to onsite; a bare country staysunknownrather than being guessed at. -
LATAM eligibility flag.
latamFriendlyis true when the role sits in a Latin American country or is remote with a scope that includes the region — "Remote - LATAM", "Americas", "must overlap GMT-5", "work from anywhere". US-built job scrapers treat those strings as noise; if you hire in the region, that flag is the product.It is deliberately conservative. A role anchored to a non-LATAM country and not marked remote is never flagged, no matter what the description says — a US-based role whose body mentions "our business in the Americas" is a business-scope mention, not a hiring signal, and treating it as one would make the flag worthless.
-
Language detection (
es/pt/en) on the posting body. -
Delta feed. Pass
postedAfterwith your previous run's timestamp and get only what's new, instead of re-pulling every board in full.
Input
{"boards": ["greenhouse:stripe","lever:leverdemo","ashby:ramp","workable:hospitable","smartrecruiters:smartrecruiters","recruitee:tether"],"postedAfter": "2026-07-01T00:00:00Z","latamOnly": true,"withSalaryOnly": false,"workMode": ["remote"],"titleIncludes": ["backend", "platform"],"maxItems": 0,"companyDomains": ["ramp.com"],"descriptionMaxChars": 5000,"failOnAnySourceError": false}
The slug is whatever appears in the board's public URL — see the table above. Only
boards is required; every filter is optional.
Set failOnAnySourceError to true when you would rather have a loud failure
than a partial result — useful if you schedule this and act on the output
automatically. It is off by default, because most callers would rather have five
platforms of data than none.
You can paste the careers URL instead of a slug. Any of the eight boards is
accepted as its public URL — https://boards.greenhouse.io/stripe works exactly like
greenhouse:stripe. Workday is the reason this exists: its boards need three values
(host, tenant and site) that only appear in the URL, and there is no public directory
of Workday tenants to look them up in.
Or skip the board entirely and pass a company domain. If you do not know which
ATS a company uses — and there is no reason you should — put the website in
companyDomains and the Actor works it out:
{ "companyDomains": ["stripe.com", "ramp.com"] }
It probes the six guessable platforms and reports what answered, in the run log
and in RUN_SUMMARY:
stripe.com uses greenhouse {"slug":"stripe","jobs":578}ramp.com uses ashby {"slug":"ramp","jobs":137}No public job board found for oldco.com {"probes":6}
Workday cannot be resolved this way, for the reason above. Paste its URL instead.
Output
One record per posting:
{"id": "greenhouse:stripe:7967890","source": "greenhouse","companySlug": "stripe","companyName": "Stripe","title": "Consumer Operations Associate","url": "https://stripe.com/jobs/search?gh_jid=7967890","locationRaw": "Mexico City","countryCode": "MX","latamFriendly": true,"workMode": "onsite","department": "Operations","employmentType": "Full-time","postedAt": "2026-07-22T15:16:54-04:00","updatedAt": "2026-07-27T11:17:30-04:00","salary": {"min": 120000,"max": 160000,"currency": "USD","period": "year","annualizedMin": 120000,"annualizedMax": 160000,"rawText": "$120,000 - $160,000","confidence": "parsed"},"language": "en","description": "...","scrapedAt": "2026-07-31T18:00:00Z"}
id is stable across runs, so you can upsert on it.
companyName comes straight from the ATS for Greenhouse, Workable, SmartRecruiters
and Recruitee. Ashby, Lever, Workday and Eightfold do not expose an employer display name
anywhere in their public JSON, so for those three it is derived from the board slug
(nubank becomes Nubank). companySlug is always the raw ATS value and is the
field to join on.
How often salary is filled depends on the market, not on the parser: US postings
are usually covered by pay-transparency laws, most LATAM postings are not. On the
public LATAM sample below, 6% of postings carry a salary. Use withSalaryOnly if
you only want the ones that do.
A RUN_SUMMARY record is written to the key-value store with per-board failures,
postings scanned vs emitted, and the filters applied — so a run that returns fewer
rows than you expected tells you why.
Every run also writes a SOURCE_STATUS record: one entry per ATS platform, so you
can tell a genuinely quiet week apart from a source that stopped answering.
{"checkedAt": "2026-08-12T12:59:00Z","sources": [{ "ats": "greenhouse", "status": "ok", "boards": 1, "boardsOk": 1,"jobsFound": 412, "jobsEmitted": 412, "errors": [] },{ "ats": "ashby", "status": "failed", "boards": 1, "boardsOk": 0,"jobsFound": 0, "jobsEmitted": 0,"errors": ["ashby:ramp: HTTP 404 (board not found)"] }]}
status is ok, partial (some boards answered, others did not) or failed. The run
finishes with a status message like 6/6 ATS OK - 1301 postings, readable from the run
list without opening anything.
Live public sample
A scheduled run of this Actor publishes a free, open sample every day, so you can check the exact output shape before paying for anything. It covers LATAM-eligible postings from a curated set of about 70 companies across Ashby, Greenhouse, Lever, Recruitee and Workable.
- Postings:
https://api.apify.com/v2/key-value-stores/crearcode~latam-tech-jobs/records/latest - Run metadata and per-source health: same URL ending in
/records/meta
No token and no signup. It refreshes daily at 07:00 UTC.
Reliability
Six of the eight are documented public JSON endpoints with no authentication and no
anti-bot layer, so there is nothing there that silently degrades when a site ships a
redesign. Workday is the exception and worth stating plainly: it sits behind bot
management, it pages 20 postings at a time whatever you ask for, it stops at 10,000
postings on the largest tenants, and it needs one extra request per posting to reach
the description and the real posting date. Set maxItems when you point it at a
company with thousands of openings.
Requests retry three times with exponential backoff; a 404 is treated as a permanent
"no such board" rather than retried. Boards are fetched five at a time — enough to be
fast, not enough to be rude. One failing board does not sink the run; all boards failing
does, loudly.
The sources are checked every day. A scheduled run hits one known-good board on each of the six platforms and alerts on any source that errors or returns nothing. If an ATS changes its API, that check fails before your run does.
A typical run across six boards reads well over a thousand postings in about ten seconds.
What this does not do
- No personal data. No recruiter or hiring-manager names, no contact details, no applicant information. This is a deliberate design constraint, not an oversight.
- No authenticated scraping and no credential sharing.
- No aggregator sites. It reads each company's own board directly, which is why the data is first-hand and the uptime is the ATS's rather than a middleman's.
companyNameis null on Lever. Lever's public postings API does not expose the company's display name, and inventing one from the slug would be a guess. The other five sources return it when the ATS publishes it.
Local development
npm installnpm run buildnpm run test:local # offline assertions + live endpoint probe
test:local checks the salary parser and the location, work-mode and LATAM classifiers
against fixtures without needing network — including a regression test for the
"business in the Americas" false positive — then probes the six live endpoints and
reports how many postings each returned.
Issues
Found a bad parse, or want a field in a different shape? Open an issue on the Actor. Include the board entry and the posting URL and it is usually a quick fix.