Greenhouse Jobs Feed + Lever, Ashby & Workable: New & Closed
Pricing
from $1.50 / 1,000 job posting rows
Greenhouse Jobs Feed + Lever, Ashby & Workable: New & Closed
Greenhouse jobs plus Lever, Ashby, Workable and Personio postings from public job boards in one flat schema with salary, location and remote fields. Change mode returns only new, changed or closed postings since your last run. No recruiter fields; emails and phone numbers removed from descriptions.
Pricing
from $1.50 / 1,000 job posting rows
Rating
0.0
(0)
Developer
Jack Valmadre
Maintained by CommunityActor stats
0
Bookmarked
1
Total users
1
Monthly active users
16 days ago
Last modified
Categories
Share
Greenhouse, Lever, Ashby & Workable Jobs Feed: New & Closed
Get the open jobs of any company that publishes its job board on Greenhouse, Lever, Ashby, Workable or Personio, in one flat table, and, on a schedule, only the postings that are new, changed or closed since your last run.
It reads the public job-board APIs and feeds these applicant-tracking systems provide for employers' careers pages (plain JSON, or Personio's XML feed; no login, no browser, usually one request per board; see Politeness), so runs are quick and cheap.
| System | What to enter | Salary fields |
|---|---|---|
| Greenhouse | greenhouse:stripe or https://boards.greenhouse.io/stripe | when the employer publishes a pay range |
| Lever | lever:spotify or https://jobs.lever.co/spotify (EU: https://jobs.eu.lever.co/...) | when the employer publishes a pay range |
| Ashby | ashby:linear or https://jobs.ashbyhq.com/linear | when the employer publishes a pay range |
| Workable | workable:skroutz or https://apply.workable.com/skroutz | never (Workable's public job list has no salary field) |
| Personio | personio:thermondo or https://thermondo.jobs.personio.de | when the employer publishes a pay range |
What you can use it for
- Keep a job board, newsletter or niche jobs site up to date with new postings and remove closed ones.
- Watch hiring at a list of companies (new teams, new locations, roles closing).
- Salary and remote-work research across employers that publish pay ranges.
- Spot stale or long-open postings (use
maxDaysOpento filter them out, or usedays_opento sort/flag them yourself). - Flag postings that have been advertised before:
reopened = truewhen the same title and location reappears after closing.
Input
| Field | What it does |
|---|---|
boards | One board per line: greenhouse:stripe, lever:spotify, ashby:linear, workable:skroutz, personio:thermondo, or a board URL (https://boards.greenhouse.io/figma, https://jobs.lever.co/spotify, https://jobs.ashbyhq.com/linear, https://apply.workable.com/skroutz, https://thermondo.jobs.personio.de). EU-hosted Lever boards (https://jobs.eu.lever.co/...) work too; EU-hosted Greenhouse boards (boards.eu.greenhouse.io), single Workable job links (https://apply.workable.com/j/...) and Workable careers sites on a company's own domain are not supported and are reported as invalid. Up to 500 per run. Also accepted as startUrls, urls or companies. |
mode | full (default): every open posting on every run, marked new / changed / unchanged, plus closed ones. changes: only new, changed and closed postings since the previous run with the same boards; the first run returns every open posting as new. Use changes for scheduled runs. |
maxRows | Stop after this many rows (each row is one charged job-row event). The input form starts at 10 so a first try costs about US$0.015; clear it (or set 0) to get every posting. When calling the API, leave it out for no limit. Also accepted as maxItems. |
includeDescription | Adds the plain-text job description (off by default; about 5–7 times larger output in our tests). Email addresses and phone numbers are removed. |
stateStoreName | Named key-value store that remembers previous runs. Set your existing store name explicitly to keep its history under limited permissions; see below for the blank-field fallback. |
resetState | Forget the history for these boards and start over. |
titleIncludes / titleExcludes | Keep postings whose title contains any of these words or phrases / leave out those that contain any of them. |
locations | Keep postings whose location, other locations or country contains any of these (e.g. Berlin, Germany, US). |
remoteOnly | Keep only postings marked remote. |
workplaceTypes | Keep postings with one of these workplace types: remote, hybrid, onsite. |
hasSalary | Keep only postings with a published pay range. |
minSalary + salaryCurrency | Keep postings whose pay range reaches at least this much per year, in this currency (e.g. 100000 and USD). |
salaryPeriodUnknownAsYear | With minSalary: treat pay ranges with no stated period (all Greenhouse ranges) as yearly. |
postedWithinDays | Keep postings the employer published at most this many days ago. |
maxDaysOpen | Leave out open postings that have been open more than this many days (by published_at; postings without a date are left out). Closed postings are still reported. |
Filters
All filters are optional; with none set you get every posting. Postings a filter leaves out are not written and not charged. Several values in one filter are alternatives (any may match); different filters must all match.
- Text (
titleIncludes,titleExcludes,locations) is case-insensitive and matches at the start of a word:engineermatches "Senior Engineering Manager",MLmatches "MLOps" but not "HTML",USmatches "USA" but not "Austin". Country is a code on Lever and Workable (US,GB), usually a name on Ashby, and absent on Greenhouse and Personio, where only the location text is searched. - Remote and workplace type use the fields each system provides. Lever and Ashby state the workplace type; Workable marks remote jobs only; Greenhouse and Personio have no such field, so there a posting counts as remote only when its location says "Remote".
- Salary floor (
minSalary) compares the top of the employer's own pay range with your floor, only in the currency you give (no exchange rates), after converting the stated period to a year (hour x 2,080, day x 260, week x 52, month x 12). Postings without a range, in another currency, or without a stated period are left out; nothing is guessed from description text. Greenhouse never states the period: setsalaryPeriodUnknownAsYearto include Greenhouse ranges as yearly. - Posted within N days uses
published_at; postings without a date are left out. Closed postings are still reported when they match your other filters, however long ago they were posted. - Maximum days open (
maxDaysOpen) keeps only open postings wheredays_openis at most N. Postings without apublished_at(so nodays_open) are left out. Closed postings are still reported. - Filters and the change feed: the history covers the whole board, whatever the filters. Changing a filter
never makes postings look new or closed. It also means that widening a filter in
changesmode does not replay postings that were already open: run once infullmode (or withresetState) to get them. - The run summary (
OUTPUT) lists the filters used and how many postings each one left out.
The board name is the part of the careers-page URL after the domain (for https://jobs.lever.co/spotify it is spotify;
for https://apply.workable.com/skroutz it is skroutz); for Personio it is the part before .jobs.personio.de
(thermondo for https://thermondo.jobs.personio.de).
How the change feed works
The actor keeps the postings it saw in a named key-value store in your own Apify account, one record per distinct
board list (the record key is a hash of the sorted boards, so the order and URL form don't matter). Schedule the actor
with the same boards and mode set to changes (for example daily) and each run returns
only what changed. Changing mode or includeDescription keeps the history. Editing the board list starts a new history for
the new list. The record is small (about 24 KB for 272 postings in our test) and named stores are kept until you delete
them.
Keeping your existing history: set stateStoreName explicitly to the store your scheduled runs already use
(usually ats-job-feed-state). Apify can then request read/write permission for that store. Keep the same store name
and boards on subsequent runs.
If you leave stateStoreName blank, the actor first tries ats-job-feed-state. If Apify denies opening that store
with HTTP 403, the actor uses ats-job-feed-state-limited instead. This is a separate history: existing records are
not copied, and the first run for your boards in that store returns every open posting as new, including postings
seen in the old store. Subsequent runs using this store retain their history. To keep using that history explicitly,
set stateStoreName to ats-job-feed-state-limited. An access error for a store you named explicitly fails the run
instead of switching stores.
- A posting is changed when its title, team, location, workplace type, employment type, salary, links or
description change. Greenhouse's
updated_atalone does not count (Greenhouse updates it without visible edits). - A closed posting appears once, on the first run after it disappeared, then never again.
- A board that fails to load (network error, 404) keeps its history and never produces
closedrows; the run summary lists it. - A run stopped early by your maximum cost per run or by
maxRowssaves history only for the postings it wrote: the rest come back on the next run, and boards it didn't reach never produceclosedrows. - Rows are written before the history is saved, so an interrupted run can repeat rows on the next run but never lose a change.
Output
One dataset row per posting, same fields for all five systems (missing values are null):
source, board, company, job_id, posting_key (source:board:job_id, stable across runs), title,
department, team, location, all_locations, country, workplace_type (remote / hybrid / onsite), remote,
employment_type, salary_min, salary_max, salary_currency, salary_interval, salary_text, url,
apply_url, published_at, updated_at, description, change_type (new / changed / unchanged / closed),
first_seen_at, days_open, reopened, closed_at, scraped_at.
days_open: integer days from published_at to the run time (open postings) or to the run time at close (closed
postings). null when published_at is missing.
reopened: true on a new posting when the same board has a previous closed posting with the same title (case-insensitive, stripped) and location. false on the first run for a board (no history to compare against). Useful for flagging roles that keep being re-advertised.
Example row (real output for Figma's Greenhouse board, 2026-09-25, description shortened):
{"source": "greenhouse", "board": "figma", "company": "Figma", "job_id": "5426468004","posting_key": "greenhouse:figma:5426468004", "title": "Account Executive, Enterprise","department": "Sales", "location": "San Francisco, CA • New York, NY • United States","salary_min": 165000.0, "salary_max": 190000.0, "salary_currency": "USD","url": "https://boards.greenhouse.io/figma/jobs/5426468004?gh_jid=5426468004","published_at": "2025-01-28T18:57:29-05:00", "change_type": "new","first_seen_at": "2026-09-25T09:41:36Z", "days_open": 604, "reopened": false, "closed_at": null}
The run summary (key-value store record OUTPUT) lists each board's status (ok, not_found, error, invalid,
duplicate), counts of new / changed / unchanged / closed postings, and a warning when a board is empty (companies
that move to another applicant-tracking system often leave an empty board behind).
What the data covers (measured)
Field coverage depends on what each employer fills in. On 21 real boards on 2026-09-25 (4,651 postings), a salary was
present on 33% of Greenhouse, 35% of Lever and 66% of Ashby postings, and a remote flag on 17%, 100% and 78%.
On Greenhouse, salary_text is the employer's label for the pay range (e.g. "Annual Base Salary Range:") and
salary_interval is usually empty.
Workable (3 real boards on 2026-09-27, 54 postings): the salary fields are always empty; country, remote and
all_locations were filled on every posting, department on 51 and employment_type on 41; workplace_type is set
only for remote jobs. Workable lists a job once per location; the actor returns it as one row with every location in
all_locations, so the row count matches the job total on the company's Workable careers page (33, 19 and 2 jobs on
these boards).
Personio (9 real boards in two samples on 2026-09-27 UTC, 578 postings): department and location were filled on all
but 2 of 578 postings, employment_type on all but 1, and published_at on every posting. A salary was on 7% of postings in one
sample (4 boards) and on 1 of 68 in the other (5 boards), and remote was set on 16% and 43%: it depends on the
employer. remote is true when any of the posting's offices has "Remote" in its name (e.g. "Remote - Germany"),
otherwise empty, never false; offices named "Hybrid …" are not flagged. country and workplace_type are always
empty (the feed has no such fields), and team is Personio's recruiting category. company is the employer's legal
entity as the feed writes it, when the feed gives one (e.g. "Thermondo GmbH", "deskbird AG"; some feeds add a number,
as in "ottonova Holding AG - 9680"); otherwise it is the board name. Postings are in the language the employer wrote
them in, often German. With
descriptions on, the actor reads the feed in English and, if some postings have no English text, once more in German
for those postings; with descriptions off it reads the English feed only.
Limitations
- Only Greenhouse, Lever, Ashby, Workable and Personio job boards. Companies using other systems (Workday, iCIMS,
SmartRecruiters, Recruitee and others) are not covered; a company that moved away shows as
not_foundor empty. - You supply the boards; the actor doesn't discover companies or search all jobs.
- Only postings the employer publishes on the public board (Ashby unlisted postings are skipped).
- A board whose address redirects to another site is reported as an error and keeps its history (no false
closedrows). Personio boards are never followed through a redirect (Personio sends unknown company names to its own website): they are reported asnot_foundand keep their history. - Personio: only boards on
<company>.jobs.personio.de(or.com) are read; careers pages on a company's own domain are not recognised. When descriptions are on, a change to a German-only description is not reported aschanged. - Personal data: recruiter and hiring-manager fields, Greenhouse custom fields and internal ids are never copied, and email addresses and phone numbers are removed from descriptions. Names of people that appear inside the free text of a description are not removed; switch descriptions off if you don't need them.
- Postings are the employers' own job ads. You are responsible for how you use and republish them.
Politeness
Usually one request per board per run (a second one for a Personio board when descriptions are on and some postings have no English text; up to 2 retries on errors), at least 1 second between requests to the same host (Lever's robots.txt asks for this), and a clear user agent. Only the public read-only endpoints are used; no applications are submitted.
Use with AI agents and other actors
Input is plain JSON, e.g. {"boards": ["greenhouse:stripe", "ashby:linear", "workable:skroutz"], "mode": "changes"}; startUrls in the
usual [{"url": "..."}] form also works. Each row has a stable posting_key for de-duplication.
Pricing
Pay per event: US$0.0015 per dataset row (job-row), plus a start fee of US$0.00005 per GB of run memory, charged once per run (at most US$0.00005 at the default 256 MB).
Every row counts: in full mode (the default) that is every open posting plus closed ones, in changes mode only
new, changed and closed postings. There is no extra charge for Apify platform usage. Apify shows the price before
you run, and you can set a maximum cost per run. When that budget (or maxRows) runs out, the run writes as many
rows as it covers (part of a board if need be), then stops, succeeds, and says so in its status message; the
OUTPUT record marks the cut board partial and the boards after it not_read. Nothing is lost in the change
feed: postings whose row wasn't written keep their saved history, so the next run with these boards still reports
them as new, changed or closed, and boards that weren't read never produce closed rows.
Support
Please use the Issues tab of this actor. We aim to respond within 14 days. This actor is built and supported with AI assistance; a human owner can be reached on request through the Issues tab.
Publisher: Madrasco. Not affiliated with Greenhouse, Lever, Ashby, Workable or Personio.