# Greenhouse & Lever Jobs: Job Listings from Company Boards (`stellalytics/ats-job-listings`) Actor

Get job listings from companies' Greenhouse and Lever job boards: title, location, department, salary range, date and link, one row per job. Name companies by website or board link. Filter by title, location, remote and date; only new jobs since your last run. Pay per job.

- **URL**: https://apify.com/stellalytics/ats-job-listings.md
- **Developed by:** [Stellalytics](https://apify.com/stellalytics) (community)
- **Categories:** Jobs, Lead generation, Automation
- **Features:** Limited permissions
- **Stats:** 2 total users, 1 monthly users, 0.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.00 / 1,000 job listeds

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## Greenhouse & Lever Jobs: Job Listings from Company Boards

Get the open jobs of any company that hires through **Greenhouse** or **Lever**, one row per job: title, location, department or team, workplace type, employment type, salary range where the company publishes one, date posted and the link to apply. Name companies by website, board link or board name, filter the jobs, and schedule it to get **only new postings** each day.

It reads the public job-board APIs that Greenhouse and Lever publish so companies and job sites can show their openings. There is no login, no browser and no API key. Thousands of companies use these two systems, from startups to large tech employers.

### What you get

- **One row per job:** `company`, `title`, `location` (and `allLocations` on Lever), `department`, `team`, `workplaceType` (remote, hybrid, on-site), `employmentType` (full-time, contract...), `postedAt`, `updatedAt`, `url` and `applyUrl`.
- **Salary ranges:** `salaryMin`, `salaryMax` and `salaryCurrency` where the company publishes pay on its board. Lever boards include them, with `salaryInterval` (for example per year); for Greenhouse boards, turn on **Include Greenhouse salary ranges** (Greenhouse doesn't say the interval, so check the job page).
- **Filters:** words in the job title, location, department or team, remote only, and posted in the last N days. You pay only for the jobs that pass.
- **Only new jobs:** for scheduled runs, it remembers the jobs it already gave you and returns only new postings.
- **Errors per company, not per run:** a company with no readable board gets one free row with an `error` saying why, and the others carry on.
- **SUMMARY record:** boards read, jobs listed, matched, already seen and written.

Sample row from the prefilled run (Airbnb's Greenhouse board):

```json
{
  "company": "Airbnb",
  "ats": "greenhouse",
  "board": "airbnb",
  "jobId": "8380007",
  "title": "Advanced Analytics Intern",
  "location": "United States",
  "department": "Intern",
  "workplaceType": "Remote",
  "salaryMin": null,
  "postedAt": "2026-11-11T21:35:28+00:00",
  "url": "https://careers.airbnb.com/positions/8380007?gh_jid=8380007",
  "error": null
}
```

### Use cases

- **Job alerts and job sites:** a daily feed of new roles at the companies you follow, filtered by title and location.
- **Hiring signals for sales and recruiting:** see which companies are hiring for which teams, and where.
- **Market and salary research:** compare openings, locations and published pay ranges across companies.
- **Feed a spreadsheet, database or AI agent** with structured job data instead of copying from careers pages.

### How to use it

1. In **Companies**, add one company per line. Any of these work:
   - a board link: `https://boards.greenhouse.io/airbnb`, `https://jobs.lever.co/palantir` (EU boards on `jobs.eu.lever.co` too)
   - a board name: `airbnb` (Greenhouse is tried first, then Lever)
   - the company's website: `example.com`. The Actor reads that company's own careers page and uses the Greenhouse or Lever board it links to.
2. Optionally filter by **Job title contains**, **Location contains**, **Department or team contains**, **Remote jobs only** and **Posted in the last N days**.
3. For a daily feed, turn on **Only jobs new since my last run** and add a schedule.
4. Run it. Jobs are in the Output tab and the counts in the SUMMARY record.

### Pricing

You pay **per job written to your dataset**, plus Apify's small start fee; the current price is on the Pricing tab. Jobs your filters remove, jobs already seen with **Only jobs new since my last run**, and companies without a readable board are never charged. Set **Maximum jobs to write**, or a maximum cost per run, to cap the cost.

### Automate it: schedules and integrations

- **Schedule** a daily run with **Only jobs new since my last run** for a feed of new postings.
- **Export and connect:** download as CSV, Excel or JSON, or send new jobs to Google Sheets, Slack, Make, Zapier or n8n through Apify's integrations.
- **API and MCP:** call it from the Apify API, or from an AI agent through the Apify MCP server.

### Limitations

- **Facts and links only.** Rows don't include the job description text: it is the employer's own writing, so the `url` links to it on the company's page.
- Only Greenhouse and Lever boards. Companies that use another system (Workday, Ashby, SmartRecruiters and others), or no public board, get an `error` row.
- For a website, the board must be linked from the company's careers page (`/careers`, `/jobs`) or homepage, and the site's robots.txt must allow reading those pages (including any site they redirect to). Otherwise use the board link or name directly.
- Salary ranges appear only where the company publishes them. Greenhouse salary lookups take one request per job that passed your filters, at most 300 per board.
- The **Only new jobs** memory is a key-value store named `ats-job-listings-state` in your Apify account. Each saved task, and each set of filters, has its own memory, so two tasks watching the same company don't hide jobs from each other. Changing a task's filters starts a new, empty memory: the next run returns (and charges) every matching job again. Delete the store to start over.
- At most 500 companies per run.

### FAQ

**Is this allowed?**
Greenhouse and Lever publish these job-board APIs so that a company's openings can be shown on other sites; the data is the same as on the public job board. The Actor doesn't log in, reads only published jobs, and outputs no applicant or recruiter data.

**How do I find a company's board name?**
Open the company's careers page and click a job. If the link starts with `boards.greenhouse.io/NAME`, `job-boards.greenhouse.io/NAME` or `jobs.lever.co/NAME`, that NAME is the board. Or just give the company's website.

**Why did a company return an error?**
The `error` column says why: no board under that name, no Greenhouse or Lever board linked from its careers page, or robots.txt doesn't allow reading the page. Error rows are free.

### Support

Found a bug or need a feature? Open an issue on the Issues tab, where fixes for broken runs are a priority. For a custom version or a question you'd rather not post publicly, email <stellalytics@gmail.com>. Never send API keys or passwords by email or in an issue.

# Actor input Schema

## `companies` (type: `array`):

One per line: a company's website (stripe.com), a Greenhouse or Lever board link (https://boards.greenhouse.io/airbnb, https://jobs.lever.co/palantir), or a board name (airbnb). For a website, the board is found on the company's own careers page.

## `titleKeywords` (type: `array`):

Keep jobs whose title contains any of these words, for example engineer, sales, data. Leave empty for all jobs.

## `locations` (type: `array`):

Keep jobs whose location contains any of these, for example London, Germany, Remote.

## `departments` (type: `array`):

Keep jobs whose department or team contains any of these, for example Engineering, Sales.

## `remoteOnly` (type: `boolean`):

Keep only jobs whose location or workplace type says remote.

## `postedWithinDays` (type: `integer`):

Keep only jobs first published in the last N days. 0 means any date.

## `onlyNewJobs` (type: `boolean`):

For scheduled runs: remembers the jobs already seen (in a key-value store named ats-job-listings-state in your account) and returns only new postings. The first run returns all jobs.

## `includeSalary` (type: `boolean`):

Greenhouse boards publish pay ranges per job; reading them takes one extra request per job (up to 300 per board). Lever boards include them anyway.

## `maxJobs` (type: `integer`):

Caps the cost: the run stops after this many jobs. 0 means no limit (your maximum cost per run still applies).

## Actor input object example

```json
{
  "companies": [
    "https://boards.greenhouse.io/airbnb",
    "https://jobs.lever.co/palantir"
  ],
  "titleKeywords": [
    "engineer",
    "data"
  ],
  "remoteOnly": false,
  "postedWithinDays": 0,
  "onlyNewJobs": false,
  "includeSalary": false,
  "maxJobs": 0
}
```

# Actor output Schema

## `results` (type: `string`):

No description

## `summary` (type: `string`):

No description

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "companies": [
        "https://boards.greenhouse.io/airbnb",
        "https://jobs.lever.co/palantir"
    ],
    "titleKeywords": [
        "engineer",
        "data"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("stellalytics/ats-job-listings").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "companies": [
        "https://boards.greenhouse.io/airbnb",
        "https://jobs.lever.co/palantir",
    ],
    "titleKeywords": [
        "engineer",
        "data",
    ],
}

# Run the Actor and wait for it to finish
run = client.actor("stellalytics/ats-job-listings").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "companies": [
    "https://boards.greenhouse.io/airbnb",
    "https://jobs.lever.co/palantir"
  ],
  "titleKeywords": [
    "engineer",
    "data"
  ]
}' |
apify call stellalytics/ats-job-listings --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,stellalytics/ats-job-listings"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/4MDbr6XD9oOduNcKL/builds/QTyvXEAcf9Xnjqx5n/openapi.json
