Multi-ATS Jobs Scraper (Greenhouse, Lever, Ashby)
Pricing
$3.00 / 1,000 job returneds
Multi-ATS Jobs Scraper (Greenhouse, Lever, Ashby)
Scrape open job listings from the three big ATS job boards β Greenhouse, Lever and Ashby β straight from their public JSON APIs. No key, no login. Pass companies as "ats:token" (e.g. greenhouse:stripe) and get every posting normalized to one clean schema.
Pricing
$3.00 / 1,000 job returneds
Rating
5.0
(1)
Developer
Actor stats
0
Bookmarked
3
Total users
1
Monthly active users
3 days ago
Last modified
Categories
Share
Multi-ATS Jobs Scraper (Greenhouse Β· Lever Β· Ashby)
Scrape open job listings straight from the public JSON APIs of the three most common applicant-tracking systems β Greenhouse, Lever and Ashby. No API key, no login, no anti-bot to fight. Point it at a list of company boards and get every posting back in one normalized schema.
Thousands of companies post their jobs through exactly these three boards. Instead of writing a scraper per company, give this actor a list like ["greenhouse:stripe","lever:spotify","ashby:ramp"] and it figures out the right endpoint for each and merges the results.
Input
| Field | Notes |
|---|---|
companies | Array of "ats:token" strings. ats is greenhouse, lever, or ashby; token is the company's board slug. e.g. greenhouse:stripe, lever:spotify, ashby:openai. |
ats + company | Convenience pair for a single board (e.g. ats: "greenhouse", company: "stripe"). Ignored when companies is set. |
maxItems | Max postings per company. 0 (default) = all open postings. |
proxyConfiguration | Optional, off by default. These public APIs have no anti-bot, so no proxy is needed. Only enable one if you hit IP-based rate limits across many boards. |
Where do I find the token?
It's the slug in the public careers URL:
- Greenhouse β
boards.greenhouse.io/<token>(also<token>.greenhouse.io) - Lever β
jobs.lever.co/<company> - Ashby β
jobs.ashbyhq.com/<name>
Output
One dataset row per job posting, deduped by url:
{"ok":true,"ats":"greenhouse","company":"stripe","title":"Account Executive, AI Sales","location":"San Francisco, CA","department":"1650 AI GTM Strategy & Solutions","employmentType":"FullTime","url":"https://stripe.com/jobs/search?gh_jid=7964697","postedAt":"2026-06-05T15:44:04-04:00","description":"Who we areβ¦ (plain text, HTML stripped)","salary":"$211.4K β $290.6K β’ Offers Equity"}
Field availability differs by ATS, so several fields can be null even on a successful row:
| Field | Greenhouse | Lever | Ashby |
|---|---|---|---|
employmentType | null (not exposed) | β (commitment) | β |
salary | null (not exposed) | best-effort (often null) | β (structured, may be null) |
department | β | β (dept / team) | β (dept / team) |
location / postedAt / url | β when present, else null | β when present, else null | β when present, else null |
title and company are always present on a success row. Every other field above is null when the board doesn't supply it β this is honest data, not a failed scrape.
Greenhouse job descriptions come HTML-entity-encoded; the actor decodes and strips them to clean plain text.
Diagnostic rows (ok:false)
When a board has no open postings, uses a wrong/retired slug, or hits a network/blocked error, the actor pushes a single ok:false diagnostic row instead of job rows, for example:
{"ok":false,"errorCode":"NO_RESULTS","error":"The request succeeded but returned no results for this input.","ats":"greenhouse","company":"acme","note":"No open postings for greenhouse:acme."}
An ok:false row means that one board had nothing to return β not that the run failed. These rows are never charged. Filter on ok:true to get only billable job postings. Empty input produces an ok:false row with errorCode: "BAD_INPUT" instead of crashing the run.
Billing & empty boards
Billed per job posting returned (job), and only for genuine ok:true rows. A board with no open postings (or a wrong/retired slug) produces a single ok:false diagnostic row explaining why β and is not charged. Network/blocked errors and empty/invalid input likewise return a coded ok:false diagnostic row instead of failing the whole run, and are never charged.
Example
{"companies":["greenhouse:stripe","greenhouse:airbnb","lever:spotify","ashby:ramp","ashby:openai"],"maxItems":0}
