# Career-Site Jobs API: Greenhouse, Lever, Ashby & more (`iiclabs/career-site-jobs-api`) Actor

Get every open job from company career sites as one clean dataset. Enter company domains or job board URLs; the job board (Greenhouse, Lever, Ashby, Workable or Recruitee) is detected automatically. Only-new mode returns just the jobs that are new or changed since your last run.

- **URL**: https://apify.com/iiclabs/career-site-jobs-api.md
- **Developed by:** [TOO EASY](https://apify.com/iiclabs) (community)
- **Categories:** Jobs, Lead generation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.50 / 1,000 job postings

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

## Career-Site Jobs API: Greenhouse, Lever, Ashby & more

**Get every open job from company career sites as one clean dataset.** Give it company domains (`stripe.com`) or job board links, and it finds each company's job board, collects every open position, and returns them in one consistent format: title, seniority, department, location, remote/hybrid/on-site, employment type, salary range (where published), posting date and description.

Turn on **Only new or changed jobs** and schedule it daily: you get, and pay for, only the jobs that appeared or changed since your last run.

### What can the Career-Site Jobs API do?

- 🔎 **Detects the job board from a domain.** Enter `stripe.com` or a careers page URL; the Actor finds the company's Greenhouse, Lever, Ashby, Workable or Recruitee board for you. Board URLs work too.
- 🧹 **One format across job boards.** Every job has the same fields whatever system the company uses, including inferred **seniority** (intern → executive), **workplace type** and **salary** where the company publishes it.
- 🆕 **Only new or changed jobs.** Delta mode remembers what you've already received, so daily runs return only fresh postings. Ideal for job alerts, lead lists and hiring-signal monitoring.
- 🎯 **Filters.** Title keywords, location keywords, remote only, and a cap per company.
- ✅ **Public data, collected politely.** Uses the job boards' own public APIs that companies publish for their careers pages. robots.txt is checked for every host and crawl delays are respected. No LinkedIn or Indeed scraping, no logins.
- ⚙️ **Everything Apify offers:** run from the API, schedule runs, export to CSV/Excel/JSON, or connect to Google Sheets, Zapier, Make, Slack and webhooks.

### What data does it return?

| Field | Example |
|---|---|
| `company` | Airbnb |
| `title` | Senior Software Engineer, Payments |
| `seniority` | senior |
| `department`, `team` | Engineering, Payments |
| `location`, `locations` | San Francisco, CA; \[San Francisco, CA, Remote - US] |
| `workplaceType`, `remote` | hybrid, false |
| `employmentType` | Full-time |
| `salaryMin`, `salaryMax`, `salaryCurrency`, `salaryInterval` | 180000, 240000, USD, year |
| `publishedAt`, `updatedAt` | 2026-09-28T14:03:11.000Z |
| `url`, `applyUrl` | Link to the posting and to the application form |
| `descriptionText`, `descriptionHtml` | Full description (can be switched off) |
| `ats`, `boardToken`, `jobId` | greenhouse, airbnb, 8184174 |
| `changeType`, `firstSeenAt` | new, 2026-10-06T08:00:00.000Z (only-new mode) |

Fields a job board doesn't provide are `null` (for example, Greenhouse doesn't publish salary ranges through its job board API).

### How to use it

1. Add companies to **Companies**: domains like `stripe.com`, or job board links like `https://boards.greenhouse.io/airbnb`, `https://jobs.lever.co/palantir`, `https://jobs.ashbyhq.com/openai`.
2. Optionally add filters (title or location keywords, remote only) and a maximum per company.
3. Click **Start**. Results appear in the **Jobs** table; the **Run summary** shows which job board was found for each company.
4. For ongoing monitoring, turn on **Only new or changed jobs** and create a daily **Schedule**.

#### Input example

```json
{
  "companies": ["stripe.com", "https://jobs.lever.co/palantir", "https://jobs.ashbyhq.com/openai"],
  "titleKeywords": ["engineer", "data"],
  "remoteOnly": false,
  "onlyNew": true,
  "includeDescription": true
}
```

#### Output example

```json
{
  "company": "Stripe",
  "input": "stripe.com",
  "ats": "greenhouse",
  "boardToken": "stripe",
  "jobId": "7310829",
  "title": "Backend Engineer, Billing",
  "seniority": null,
  "department": "Engineering",
  "team": null,
  "location": "Dublin, Ireland",
  "locations": ["Dublin, Ireland"],
  "remote": null,
  "workplaceType": null,
  "employmentType": null,
  "url": "https://stripe.com/jobs/search?gh_jid=7310829",
  "applyUrl": "https://stripe.com/jobs/search?gh_jid=7310829",
  "publishedAt": "2026-09-30T13:20:00.000Z",
  "updatedAt": "2026-10-02T09:12:44.000Z",
  "salaryMin": null,
  "salaryMax": null,
  "salaryCurrency": null,
  "salaryInterval": null,
  "descriptionText": "…",
  "descriptionHtml": "…",
  "changeType": "new",
  "firstSeenAt": "2026-10-06T08:00:00.000Z",
  "scrapedAt": "2026-10-06T08:00:00.000Z"
}
```

*(Illustrative values.)*

### How much does it cost?

You pay only for results (pay per event); no monthly rental and no charge for compute.

| Apify plan | Per 1,000 jobs | Per company detected from a domain |
|---|---|---|
| Free | $3.00 | $0.005 |
| Bronze (Starter) | $2.50 | $0.005 |
| Silver (Scale) | $2.00 | $0.005 |
| Gold (Business) | $1.50 | $0.005 |

- **Job:** each job saved to your dataset. In only-new mode, only new or changed jobs count.
- **Company detected:** charged only when the Actor finds the job board from a domain or careers page. Job board URLs you enter directly are free of this charge. Companies with no supported job board are never charged.
- Apify adds a tiny per-run start fee.

The **Pricing** tab always shows the current prices. You can set a **maximum cost per run**: the Actor stops cleanly when it's reached and says so in the status message.

**Examples (Free plan prices):**

- The prefilled test run (3 companies, 20 jobs each) costs about **$0.19**.
- 50 companies with about 60 open jobs each: about 3,000 jobs = **$9.00** on the first run ($4.50 on Business).
- The same 50 companies checked daily with only-new mode: typically a few dozen new or changed jobs per day = **a few cents per day**.

### FAQ

**Which job boards are supported?**
Greenhouse, Lever (including Lever's EU instance), Ashby, Workable and Recruitee. If a company uses another system, the run summary marks it as "not_found" and you aren't charged for it.

**How is the job board found from a domain?**
The Actor looks for job board links on the company's careers, jobs and home pages. If there are none, it checks for a job board named after the company and, for Greenhouse, Workable and Recruitee, confirms the board's company name matches (Ashby and Lever boards named after the company are accepted for names of 4+ characters). Each result in the run summary shows how the board was found (`url`, `page` or `guess`). For guaranteed matches, enter the job board URL.

**How does "only new or changed jobs" work?**
The Actor remembers every job it delivered, per company and per **delta state name**, in a key-value store in your account. A job counts as changed when its title, location, department, team, employment type, workplace type, salary or description changes. Jobs that disappear are forgotten, so if they're reposted they count as new. Use different state names for different schedules.

**Is this legal?**
The Actor reads public job postings through the job boards' public APIs, which companies use to show jobs on their own careers pages. Lever's API documentation, for example, states that published postings "may be scraped by third parties". robots.txt is respected for every host. You're responsible for using the data in line with the laws that apply to you. Job postings contain no personal data beyond what companies publish.

**Why is a field empty?**
Each job board publishes different information. Salary ranges, for example, come from Ashby, Lever and Recruitee only when the company publishes them; Greenhouse and Workable job board APIs don't include salaries.

**Can I use it from my code or AI agent?**
Yes: through the Apify API, the JavaScript and Python clients, or Apify's MCP server. The output is described by the Actor's dataset schema.

### Support

Questions, bugs or a job board you'd like supported: use the **Issues** tab or email **support+jobs@iiclabs.com**. We usually reply the same day.

Whether the Actor worked well for you or not, a rating on the **Reviews** tab of [its Store page](https://apify.com/iiclabs/career-site-jobs-api) helps us improve it and helps other people find it.

# Actor input Schema

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

Company website domains (stripe.com), careers page URLs, or job board URLs such as https://boards.greenhouse.io/airbnb, https://jobs.lever.co/palantir, https://jobs.ashbyhq.com/openai, https://apply.workable.com/<company> or https://<company>.recruitee.com. For a domain or careers page the job board is detected automatically.

## `onlyNew` (type: `boolean`):

Return (and charge for) only jobs that are new or changed since your previous run with the same delta state name. The first run returns all jobs and remembers them. Ideal for daily schedules and job alerts.

## `deltaStateName` (type: `string`):

Separate memory for different monitoring setups, e.g. one name per schedule. Only used with "Only new or changed jobs".

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

Keep only jobs whose title contains at least one of these words (case-insensitive), e.g. engineer, sales. Leave empty for all jobs.

## `locationKeywords` (type: `array`):

Keep only jobs whose location contains at least one of these words, e.g. London, Germany, Remote.

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

Keep only jobs marked as remote.

## `maxJobsPerCompany` (type: `integer`):

Stop after this many jobs per company. 0 means no limit. The prefilled 20 keeps a first test run small and cheap; set 0 to get every open job.

## `includeDescription` (type: `boolean`):

Include the full job description as text and HTML. Turn off for smaller, faster results.

## Actor input object example

```json
{
  "companies": [
    "airbnb.com",
    "https://jobs.lever.co/palantir",
    "https://jobs.ashbyhq.com/openai"
  ],
  "onlyNew": false,
  "deltaStateName": "default",
  "remoteOnly": false,
  "maxJobsPerCompany": 20,
  "includeDescription": true
}
```

# Actor output Schema

## `jobs` (type: `string`):

One item per open job (or per new or changed job in only-new mode).

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

Per company: the detected job board, jobs found, jobs saved, and companies without a supported job board.

# 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": [
        "stripe.com",
        "https://jobs.lever.co/palantir",
        "https://jobs.ashbyhq.com/openai"
    ],
    "maxJobsPerCompany": 20
};

// Run the Actor and wait for it to finish
const run = await client.actor("iiclabs/career-site-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 = {
    "companies": [
        "stripe.com",
        "https://jobs.lever.co/palantir",
        "https://jobs.ashbyhq.com/openai",
    ],
    "maxJobsPerCompany": 20,
}

# Run the Actor and wait for it to finish
run = client.actor("iiclabs/career-site-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 '{
  "companies": [
    "stripe.com",
    "https://jobs.lever.co/palantir",
    "https://jobs.ashbyhq.com/openai"
  ],
  "maxJobsPerCompany": 20
}' |
apify call iiclabs/career-site-jobs-api --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,iiclabs/career-site-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/iLihPuD4zRg9sAOL6/builds/wujDjejdD1YWgEBhf/openapi.json
