# Greenhouse Jobs API: Every Job with Description & Salary (`ailu_studio/greenhouse-jobs-api`) Actor

Greenhouse jobs API: every open job on any Greenhouse board with full description, departments, offices and published pay ranges (salary min/max). Bulk board URLs or slugs; keyword, department, location and date filters. No login.

- **URL**: https://apify.com/ailu_studio/greenhouse-jobs-api.md
- **Developed by:** [Ailu Studio](https://apify.com/ailu_studio) (community)
- **Categories:** Jobs, Lead generation, Developer tools
- **Security:** Limited permissions
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.50 / 1,000 jobs

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.

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 Jobs API: every open job from any Greenhouse board, with full description and published pay ranges

Many companies (Airbnb, Stripe, Discord, Figma, Dropbox and more) host their careers page on Greenhouse at `boards.greenhouse.io/<slug>` or `job-boards.greenhouse.io/<slug>`. This Actor reads the public Greenhouse Job Board API and returns every open job as a clean row: title, departments, offices, locations, workplace type, first-published date, the **full description** (text or HTML) and the employer's **published pay ranges** (salary min/max/currency, one row per job, all ranges kept). Paste any number of board URLs or slugs, filter by keyword, department, location and posting age. It reads the boards you name live (one request per board, so results are as fresh as the careers page), returns Greenhouse's own pay-transparency ranges as numbers, needs no API key, and costs $1.50 per 1,000 jobs versus $2.00 on the free plan for the most-used Greenhouse Actor in the Store.

### Use cases

- **Job aggregation**: feed Greenhouse postings from hundreds of companies into a job board, newsletter or internal search.
- **Salary benchmarking**: collect published pay ranges by title, location and company (pay-transparency data, not estimates).
- **Hiring signals for sales and investors**: which departments and locations a target account is staffing up.
- **Candidate alerts**: run daily with `postedWithinDays: 1` and a keyword list.
- **AI matching**: descriptions arrive as plain text, ready for embedding or classification.

### Input

| Field | Default | Meaning |
|---|---|---|
| `boards` | `["airbnb", "stripe"]` | Greenhouse board URLs (`boards.greenhouse.io/<slug>`, `job-boards.greenhouse.io/<slug>`, embed URL with `?for=<slug>`, a job URL) or bare slugs. |
| `keywords` | – | Keep jobs whose title or description contains any of these words. |
| `locations` | – | Keep jobs whose location contains any of these strings; `"remote"` also matches remote workplace type. |
| `departments` | – | Keep jobs whose department name contains any of these strings. |
| `postedWithinDays` | `0` | Only jobs first published in the last N days (0 = off). |
| `includeSalaryRanges` | `true` | Request pay-transparency ranges; costs no extra requests. |
| `descriptionFormat` | `text` | `text`, `html`, `both` or `none`. |
| `maxItems` | `200` | Cap on returned jobs for the whole run. |

```json
{ "boards": ["https://job-boards.greenhouse.io/stripe", "airbnb", "discord"], "departments": ["Engineering"], "locations": ["Remote", "New York"], "postedWithinDays": 7, "maxItems": 500 }
```

### Output

| Field | Type | Meaning |
|---|---|---|
| `id`, `sourceId` | string | `greenhouse:<slug>:<jobId>` and the Greenhouse job ID. |
| `company`, `companySlug` | string | Company name from the board and the board slug. |
| `title` | string | Job title. |
| `department`, `team`, `departments`, `offices` | string, string, string\[], string\[] | Greenhouse departments and offices. |
| `locations`, `isRemote`, `workplaceType` | string\[], boolean, string | Location text; remote/hybrid/onsite when the board publishes a Workplace Type field. |
| `employmentType` | string | Employment type custom field when present. |
| `salaryMin`, `salaryMax`, `salaryCurrency`, `salaryInterval`, `salaryRaw` | number, number, string, string, string | Published pay range(s); `null` when the employer publishes none. |
| `payRanges` | object\[] | Every range with its title (e.g. one per country). |
| `requisitionId`, `internalJobId`, `applicationDeadline`, `language` | string | Extra posting metadata. |
| `postedAt`, `updatedAt` | ISO 8601 | First publication and last update (UTC). |
| `url`, `applyUrl` | string | Public posting and application page. The Actor never applies. |
| `descriptionText`, `descriptionHtml` | string | Full description in the requested format(s). |
| `fetchedAt` | ISO 8601 | Run time. |

```json
{
  "id": "greenhouse:airbnb:8231416", "sourceId": "8231416", "source": "greenhouse", "companySlug": "airbnb", "company": "Airbnb",
  "title": "Associate Principal, Procurement Innovation Supplier Programs", "department": "Financial Planning and Analysis", "team": null,
  "locations": ["United States"], "isRemote": true, "workplaceType": "remote", "employmentType": null,
  "postedAt": "2026-09-24T22:17:39.000Z", "updatedAt": "2026-09-30T00:00:54.000Z",
  "url": "https://careers.airbnb.com/positions/8231416?gh_jid=8231416", "applyUrl": "https://careers.airbnb.com/positions/8231416?gh_jid=8231416",
  "departments": ["Financial Planning and Analysis"], "offices": ["United States"], "requisitionId": "ONE", "internalJobId": "3562002",
  "applicationDeadline": null, "language": "en",
  "payRanges": [{ "title": "Pay Range", "min": 102000, "max": 120000, "currency": "USD", "interval": "year" }],
  "salaryMin": 102000, "salaryMax": 120000, "salaryCurrency": "USD", "salaryInterval": "year", "salaryRaw": "USD 102,000–120,000 (Pay Range)",
  "descriptionText": "Airbnb was born in 2007 when two hosts welcomed three guests to their San Francisco home, …", "descriptionHtml": null,
  "fetchedAt": "2026-11-04T11:31:16.267Z"
}
```

### How it works and limits

- One request per board: `GET boards-api.greenhouse.io/v1/boards/<slug>/jobs?content=true&pay_transparency=true` returns every published job with its description and pay ranges. Requests are spaced 300 ms apart and retried on 429/5xx.
- Pay ranges appear only when the employer fills Greenhouse's pay-transparency fields (on the Airbnb board 176 of 210 jobs had them on 2026-11-04; on Stripe none). Salaries written only inside the description text are not parsed.
- When a job has ranges in several currencies, the flat salary fields use the first range; `payRanges` keeps them all. `salaryInterval` comes from the range title ("Annual", "Hourly"), otherwise it is inferred from the amount.
- Boards are read in the order given; once `maxItems` is reached the remaining boards are skipped and listed in the run summary (`OUTPUT` record).
- Only public, published boards. Companies that use Greenhouse behind their own careers site still work when you pass the Greenhouse slug (find it in the "Apply" link: `?for=<slug>` or `greenhouse.io/<slug>`).
- Not covered: internal job boards, application forms, candidate data.

### Pricing

Pay per result: **$1.50 per 1,000 rows** (`job` event). Platform usage is billed separately by Apify. Removed/free rows are not charged.

### Legal

Not affiliated with Greenhouse Software, Inc. or the employers. Uses the public Greenhouse Job Board API only. Data licence/terms: https://developers.greenhouse.io/job-board.html. Job content belongs to the employers who published it.

### FAQ

**Where do I find a company's slug?** Open its careers page and click a job: the URL or the "Apply" link contains `greenhouse.io/<slug>` or `?for=<slug>`. Paste that URL as is.

**Why is salary empty for some jobs?** The employer did not publish a pay range in Greenhouse. Only employer-published ranges are returned, never estimates.

**Can I get only new jobs every day?** Set `postedWithinDays: 1` and schedule a daily run, or use the *Job Change Tracker* Actor for new/updated/removed detection.

**Does it handle big boards?** Yes. A 750-job board is a single request; raise `maxItems` to export everything.

# Actor input Schema

## `boards` (type: `array`):

Greenhouse job board URLs or board slugs, e.g. "https://boards.greenhouse.io/airbnb", "https://job-boards.greenhouse.io/stripe", "https://boards.greenhouse.io/embed/job_board?for=figma" or just "discord". The slug is the part after greenhouse.io/.

## `keywords` (type: `array`):

Only return jobs whose title or description contains at least one of these words (case-insensitive), e.g. \["engineer", "data"]. Leave empty for all jobs.

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

Only return jobs whose location contains one of these strings (case-insensitive), e.g. \["New York", "Canada"]. "Remote" also matches jobs whose workplace type is remote.

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

Only return jobs whose Greenhouse department name contains one of these strings (case-insensitive), e.g. \["Engineering", "Sales"]. Leave empty for all departments.

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

Only return jobs first published in the last N days (0 = no date filter). Use 1 for a daily run that only picks up new postings.

## `includeSalaryRanges` (type: `boolean`):

Ask Greenhouse for pay-transparency ranges and fill salaryMin, salaryMax and salaryCurrency when the employer publishes them. Costs no extra requests.

## `descriptionFormat` (type: `string`):

Plain text suits AI processing and spreadsheets; HTML keeps headings and bullet lists; "none" drops the description to keep rows small.

## `maxItems` (type: `integer`):

Upper limit on returned jobs for the whole run (default 200). Raise it for full exports; large boards such as Stripe have 700+ jobs.

## Actor input object example

```json
{
  "boards": [
    "airbnb",
    "stripe",
    "https://job-boards.greenhouse.io/discord"
  ],
  "keywords": [],
  "locations": [],
  "departments": [],
  "postedWithinDays": 0,
  "includeSalaryRanges": true,
  "descriptionFormat": "text",
  "maxItems": 200
}
```

# Actor output Schema

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

All rows in the default dataset.

# 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 = {
    "boards": [
        "airbnb",
        "stripe",
        "https://job-boards.greenhouse.io/discord"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("ailu_studio/greenhouse-jobs-api").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 = { "boards": [
        "airbnb",
        "stripe",
        "https://job-boards.greenhouse.io/discord",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("ailu_studio/greenhouse-jobs-api").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 '{
  "boards": [
    "airbnb",
    "stripe",
    "https://job-boards.greenhouse.io/discord"
  ]
}' |
apify call ailu_studio/greenhouse-jobs-api --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,ailu_studio/greenhouse-jobs-api"
        }
    }
}
```

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/mPW4G6abyZWNpeYOT/builds/F81hLuxaaXL3sLeRN/openapi.json
