Greenhouse, Lever & Ashby Jobs: New & Closed Roles
Pricing
from $1.50 / 1,000 jobs
Greenhouse, Lever & Ashby Jobs: New & Closed Roles
Job postings from company career boards on Greenhouse, Lever and Ashby, in one format, from their public APIs. Schedule it to get only new and closed roles. Filter by title, location, remote and salary. No proxy, no browser, pay per job.
Pricing
from $1.50 / 1,000 jobs
Rating
0.0
(0)
Developer
JP Data Lab
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
5 days ago
Last modified
Security
Limited permissionsShare
Get job postings straight from company career boards on Greenhouse, Lever and Ashby, in one clean format. Run it once, or schedule it and receive only new roles, plus the roles that closed. No API key, no browser and no proxy.
Every row comes from the platform's public job board API, so you get what the employer published: title, department, location, workplace type, salary, description and the link to apply.
Use it to build a job board, send role alerts, track competitors' hiring, find companies hiring for what you sell, or give an AI agent fresh postings to match against a CV.
Quick start
Read a few companies. Use a name, a career board URL, or platform:slug:
{ "companies": ["stripe", "https://jobs.lever.co/spotify", "ashby:ramp"] }
Daily alert for remote engineering roles at those companies, with closed roles. Schedule this and connect the run to Slack, email or a webhook:
{"companies": ["stripe", "lever:spotify", "ashby:ramp"],"onlyNew": true,"includeClosed": true,"titleKeywords": ["engineer", "engineers"],"excludeTitleKeywords": ["intern"],"remoteOnly": true}
Search the bundled directory instead of listing companies:
{"directoryCategories": ["ai", "fintech"],"titleKeywords": ["product manager"],"locationKeywords": ["London", "Remote"],"minAnnualSalary": 120000,"maxJobs": 200}
Finding a company
| You enter | What happens |
|---|---|
stripe | Looked up in the directory. If it is not there, tried on Greenhouse, Lever and Ashby in that order, and the first board with jobs is used |
https://job-boards.greenhouse.io/stripe | Greenhouse, Lever (including EU) and Ashby board URLs are recognized |
greenhouse:stripe, lever:spotify, lever-eu:acme, ashby:ramp | Read exactly that board |
A name can match a different company with the same board name. companiesResolved in RUN_SUMMARY shows which board was used. Use platform:slug when you need to be sure. Company names on Lever and Ashby come from the directory or the board name, because those APIs do not return one.
The directory holds 333 boards that had open jobs when they were checked against the official APIs: 189 on Greenhouse, 123 on Ashby and 21 on Lever. It is a starting point and not a list of every employer. Any public board works through companies.
How onlyNew works
- First run: outputs the newest matching jobs up to your limits and marks all other matching jobs as seen. You are not charged for those.
- Later runs: outputs only jobs not seen before. If there are more than
maxJobsPerCompany, the rest wait for the next run. - Nothing new: the board's API is asked whether anything changed. If not, it is not downloaded again and you pay no result charges.
- Closed jobs: with
includeClosed, a job you received earlier that has left the board is output once withstatus: "closed". The platforms do not say why a job left: it may be filled, cancelled or reposted under a new ID. - Changing a filter starts a fresh record for that board.
postedWithinDaysand the limits do not. - A board that suddenly returns no jobs at all is not treated as closing everything. It is counted under
emptyBoardsKept.
The record is saved in a key-value store named ats-job-boards-seen in your Apify account. Delete it to start again. Set monitorName to keep two schedules with the same search separate.
Output
One row per job:
{"id": "ashby:ramp:34413f8d-26bf-4bbc-8ade-eb309a0e2245","status": "open","ats": "ashby","board": "ramp","company": "Ramp","title": "Security Engineer, Cloud","department": "Engineering","team": "Backend","location": "New York, NY (HQ)","locations": ["New York, NY (HQ)", "Remote (Canada)", "Remote (US)", "Miami, FL"],"country": "USA","workplaceType": "hybrid","employmentType": "Full-time","postedAt": "2026-04-07T17:12:35Z","updatedAt": null,"salaryMin": 211400,"salaryMax": 290600,"salaryCurrency": "USD","salaryInterval": "year","salaryText": "$211.4K - $290.6K","salarySource": "field","url": "https://jobs.ashbyhq.com/ramp/34413f8d-26bf-4bbc-8ade-eb309a0e2245","applyUrl": "https://jobs.ashbyhq.com/ramp/34413f8d-26bf-4bbc-8ade-eb309a0e2245/application","description": "Full text, up to 50,000 characters.","descriptionHtml": null,"closedAt": null,"fetchedAt": "2026-11-02T00:00:00Z"}
Dates are UTC. Fields a platform does not provide are null. Closed rows carry the title, location and link from the earlier run, with closedAt set.
What each platform provides:
| Field | Greenhouse | Lever | Ashby |
|---|---|---|---|
workplaceType | Read from the location text, otherwise null | Yes | Yes |
employmentType | No | Yes, in the employer's wording | Yes |
country | No | Yes (ISO code) | Yes, in the employer's wording, often missing |
team | No | Yes | Yes |
updatedAt | Yes | No | No |
| Salary | From the description | Field, or from the description | Field, or from the description |
salarySource is field when the platform provides the pay range, and description when it was read from the text. With description, the first range in the text is used, and many employers list several ranges by region. Check salaryText and the posting before relying on it.
Personal details
The public job APIs do not return recruiter or hiring manager details, and this Actor does not read Greenhouse's custom metadata field. Descriptions are written by employers and can mention people, so email addresses, phone numbers and names in phrases such as "reports to Jane Doe" are replaced with [email removed], [phone removed] and [name removed]. In a check of 3,906 jobs, 2 descriptions named a person this way. This cannot catch every mention. detailsRemoved in RUN_SUMMARY counts the replacements.
Input
| Field | Default | Meaning |
|---|---|---|
companies | 3 examples | Names, board URLs or platform:slug, up to 5,000 boards in total |
directoryCategories | none | Also read the bundled directory: all, ai, fintech, devtools, security, saas, consumer, health, crypto, climate, hardware |
onlyNew | false | Output only jobs not seen in earlier runs |
includeClosed | false | With onlyNew, also output jobs that left the board |
monitorName | none | Keeps two schedules with the same search separate |
titleKeywords | none | Keep jobs whose title contains any of these |
excludeTitleKeywords | none | Leave out jobs whose title contains any of these |
locationKeywords | none | Keep jobs whose location contains any of these |
departmentKeywords | none | Keep jobs whose department or team contains any of these |
descriptionKeywords | none | Keep jobs whose description contains any of these |
remoteOnly | false | Only fully remote jobs. Hybrid is left out |
postedWithinDays | 0 | Only jobs posted in the last N days |
onlyWithSalary | false | Only jobs with a pay range |
minAnnualSalary | 0 | Range reaches this yearly amount, in the job's own currency. Hourly and monthly pay are converted |
includeDescription | true | Add description |
includeHtml | false | Add descriptionHtml |
maxJobsPerCompany | 50 | Newest first |
maxJobs | 1000 | Total for the run |
Keywords ignore case and accents. English words match whole words, so engineer does not match engineers: add both forms.
When a board fails
One bad board does not stop the run, and it costs nothing. RUN_SUMMARY lists each one under boardsFailed with the reason. The run fails only if no board could be read.
{"boardsRequested": 3,"boardsRead": 2,"boardsUnchanged": 0,"boardsFailed": [{ "company": "acme", "reason": "no job board found on Greenhouse, Lever or Ashby" }],"boardsNotReached": 0,"firstReadBoards": 0,"jobsRead": 540,"pushed": 100,"closed": 0,"seenBefore": 0,"filteredOut": 400,"overLimit": 40,"detailsRemoved": 12,"sources": { "greenhouse": { "fetched": 500, "boards": 1 }, "ashby": { "fetched": 40, "boards": 1 } }}
boardsNotReached counts boards left unread because the run hit maxJobs or your spending limit. overLimit counts matching jobs left out by the limits.
Long runs can be moved to another server by Apify. The run saves its progress and continues where it stopped instead of starting over. A run of all 333 boards with no limits took about 23 minutes and returned about 36,500 jobs.
What it respects
- Official APIs only. It reads the documented public endpoints of Greenhouse's Job Board API, Lever's Postings API and Ashby's job posting API. It does not open career pages or Workday, and SmartRecruiters is left out because its robots.txt disallows the API.
- robots.txt. It is checked for each host. There is no switch to override it.
- Server load. At least one second between requests to the same host, longer if
Crawl-delayasks for it, up to 5 seconds. Failed requests are retried twice at most. - Honest identification. Requests carry a descriptive User-Agent with a link to this page. There is no proxy and no browser disguise.
Limits
- Only currently published jobs. The platforms do not provide closed jobs or history, so run it on a schedule to build your own archive.
- Only companies that use these three platforms and publish a board. Many large employers use Workday or their own system.
- Boards over 60 MB are skipped.
Job postings belong to the employers who wrote them, and this Actor is not affiliated with Greenhouse, Lever, Employ or Ashby. You are responsible for how you use the data.
Pricing
Pay per job delivered, plus a small charge per run. Failed boards, jobs filtered out, jobs already seen and unchanged boards are free. A closed row counts as one job. Set maxJobs or a spending limit in the run options to control the cost.