# Greenhouse, Lever & Ashby Jobs Scraper + Salary (`meridianlabs/greenhouse-lever-ashby-jobs-scraper`) Actor

Scrape open jobs from Greenhouse, Lever, Ashby, Workable, Recruitee and Teamtailor with salary normalised to min, max, currency and period. $2 per 1,000 jobs. Paste board URLs, domains or company names: the system is detected for you, and unsupported companies are free.

- **URL**: https://apify.com/meridianlabs/greenhouse-lever-ashby-jobs-scraper.md
- **Developed by:** [Meridian Labs](https://apify.com/meridianlabs) (community)
- **Categories:** Jobs, Automation, Lead generation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$2.00 / 1,000 jobs

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

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 & Ashby Jobs** reads the open jobs of any company on **Greenhouse, Lever, Ashby, Workable, Recruitee or Teamtailor**, straight from the company's public job board, and gives every job a **normalised salary**: `min`, `max`, `currency` and `period` (hour, day, week, month or year), from the hiring system's own pay field or the ad text, with every pay zone or level. Paste job-board URLs, careers page URLs, plain domains (`company.com`) or company names: the hiring system is detected for you, and **every company gets a free status row** saying what was found. The input form is pre-filled, so the easiest way to try it is to click **Start** (about $0.09).

![Greenhouse, Lever & Ashby Jobs result: salaries as published on Greenhouse, Lever, Ashby, Recruitee, Teamtailor and Workable, normalised to min, max, currency and period](https://raw.githubusercontent.com/leewilliam200/meridianlabs-apify-assets/main/greenhouse-lever-ashby-jobs-scraper/greenhouse-lever-ashby-normalised-salary-result.jpg)

It's built for **recruiters and sourcers**, **sales and market-intelligence teams tracking who is hiring**, **salary and labour-market researchers**, **job-board builders** and **AI agents** that need clean, structured job data from company career pages.

### What does the Greenhouse, Lever & Ashby jobs scraper do?

For each company you give it, it finds the company's job board and returns one row per open job:

- 💰 **Normalised salary** (`salary`): `{min, max, currency, period, source, raw_text, basis, tiers, eu_pay_range}`, e.g. `$59,500 — $85,000 USD` becomes `59500`, `85000`, `USD`, `year`.
- 🏷️ **Job basics:** `title`, `department`, `employment_type` (full\_time, part\_time, contract, internship…), `posted_at`, `updated_at`, `url`, `apply_url`.
- 📍 **Location:** the location as published plus `city`, `region` and an ISO `country` code, and `workplace` (remote, hybrid or onsite) with a strict `remote` flag (fully remote only).
- 📝 **Description** as plain text or HTML (or none), with personal email addresses and phone numbers removed.
- 🔁 **Monitor mode:** only jobs that are new or changed since your last run, plus free notices for jobs that closed.
- 🆔 **Stable IDs** (`greenhouse:tubitv:8099700`) that stay the same across runs, and the `source_url` every row came from.

### Which hiring systems are supported?

| System | Found from | Salary source |
|---|---|---|
| **Greenhouse** | `job-boards.greenhouse.io/<company>`, embedded boards, careers pages | Greenhouse's pay-transparency block, else the ad text |
| **Lever** (US and EU) | `jobs.lever.co/<company>` | Lever's salary range field, else the ad text |
| **Ashby** | `jobs.ashbyhq.com/<company>` | Ashby's compensation tiers, else the ad text |
| **Workable** | `apply.workable.com/<company>`, embedded widgets | the ad text |
| **Recruitee** | `<company>.recruitee.com` or the company's own careers domain | Recruitee's salary field, else the ad text |
| **Teamtailor** | `<company>.teamtailor.com` or the company's own careers domain | the ad text |

**Not supported, and never charged:** Workday, iCIMS, SmartRecruiters, Personio, SAP SuccessFactors, Oracle Taleo, Eightfold, BambooHR and others. Their public endpoints are blocked by robots.txt or bot checks, or their terms don't allow this use. When a company uses one of them you get a free status row with `status: "not_supported"` naming the system, for example *"The board URL is on Workday. Workday is not supported…"*, so you know exactly why there are no jobs and can move on.

### How is the salary normalised?

Pay is read from the hiring system's own pay field first (`source: "ats_field"`), and from the ad text otherwise (`source: "description_text"`), in English, Dutch, German, French, Spanish, Polish and the Nordic languages, with European number formats (`€ 3.035 - € 4.052 bruto per maand`) and hourly, monthly and annual periods.

- **Every pay range, not just the first.** Postings that list pay zones or levels ("Zone 1 … Zone 4", medior/senior) get all of them in `tiers`, each with its `label`; the headline `min`/`max` is the first one.
- **Base pay first.** When a posting shows both base pay and OTE / total compensation, the base range is the headline and `basis` says `"base"`. If only OTE is given you get it with `basis: "ote"`.
- **Typos flagged, not hidden.** If an employer types `73.8` in an annual pay field (meaning 73,800), you get the number as entered with `suspect: true` and the reason.
- **EU pay transparency.** `eu_pay_range` is `true` for jobs in the EU/EEA that publish pay (the EU Pay Transparency Directive 2023/970), `false` outside it and `null` when the country is unknown.
- **Tested:** on 50 fresh jobs showing pay (September 2026), 49 were read exactly right: values, currency, period and every tier.

### Why use this job scraper?

- 💰 **Salary you can sort and filter**, not a string: comparable `min`/`max`/`period` across systems, countries and currencies.
- 🔎 **Paste anything.** A board URL resolves with a single request. For a domain it scans the careers pages and checks the six systems' public APIs; in our test on 50 fresh companies it found the right board for 47 from their domain alone. A board is only reported after its API answered, so it doesn't return another company's jobs.
- 🧾 **Clean billing.** You pay per job saved. Company status rows, unsupported and not-found companies, duplicates and closed-job notices are free. The same board given twice is fetched and charged once, and a restarted run never charges a job twice.
- 🔁 **Monitoring that doesn't bill you for nothing.** In monitor mode only new or changed jobs are saved and charged.
- 🛡️ **Personal-data clean.** Individual people's email addresses and phone numbers are removed from descriptions, and Recruitee's per-job inbox address is never output. Role mailboxes such as careers@ stay, because that's how candidates apply.
- 🤝 **Polite and simple.** Public job-board endpoints only: no login, no API keys, no proxies. robots.txt is obeyed, including Lever's crawl delay, with one request at a time per hiring system.
- 🤖 **AI-agent ready.** A documented output schema, table views and stable field names. It works from the Apify API, integrations (Make, Zapier, n8n, Google Sheets) and MCP clients.

### How do I scrape jobs from Greenhouse, Lever or Ashby?

1. Paste your **companies**, one per line: job-board URLs work best, but careers page URLs, domains and names also work.
2. Optionally add **filters**: title keywords, locations, fully remote only, posted within N days, only jobs showing a salary.
3. Choose the **mode**: all open jobs, or monitor for new and changed jobs only.
4. Click **Start**. Open the **Jobs** view, or export JSON, CSV or Excel. The **Companies** view shows what happened with each company.

![Greenhouse, Lever & Ashby Jobs input form: a list of job-board URLs, careers pages, domains or company names](https://raw.githubusercontent.com/leewilliam200/meridianlabs-apify-assets/main/greenhouse-lever-ashby-jobs-scraper/greenhouse-lever-ashby-jobs-input-form.png)

### How much does it cost to scrape jobs?

**$2 per 1,000 jobs ($0.002 per job saved).** That's the only charge.

- ✅ **Charged:** each job row saved to your dataset, after your filters and `maxJobsPerCompany`.
- 🆓 **Free:** company status rows; companies on unsupported systems (`not_supported`); companies with no board found (`not_found`); boards that failed to load; duplicates; closed-job notices in monitor mode; anything skipped by your spending limit or the run's time limit.
- 🔁 **Monitor mode:** only **new or changed** jobs are charged. Unchanged jobs cost nothing. The first run of a monitor sees every job as new.
- Examples: a company with 40 open jobs = $0.08; 100 companies with 30 jobs each = $6; a daily monitor on the same 100 companies that finds 50 new or changed jobs = $0.10 that day.
- **Free to try:** Apify's free plan includes $5 of platform usage every month, which covers about **2,500 jobs** here. Platform usage is included in the price.
- Set a **maximum cost per run** and the Actor stops exactly there. The status rows show how many jobs were not saved because of it, and in monitor mode those jobs are still "new" next time.

### Input

| Field | What it does |
|---|---|
| `companies` | Job-board URLs, careers page URLs, domains or company names, one per line. Duplicates are removed. |
| `systems` | Only use these hiring systems (default: all six). |
| `titleKeywords` / `excludeTitleKeywords` | Keep / drop jobs whose title contains any of these words (whole words, case-insensitive). |
| `locations` | Keep jobs whose location, city or region contains one of these, or whose country matches a 2-letter code (`US`, `DE`). |
| `remoteOnly` | Fully remote jobs only (hybrid isn't remote). |
| `postedWithinDays` | Jobs first published in the last N days. |
| `onlyWithSalary` | Only jobs that show a salary. |
| `mode` | `all` (every open job) or `newSinceLastRun` (monitor: new or changed jobs only, plus free closed notices). |
| `monitorName` | Separate memories for separate watch lists (monitor mode). |
| `includeDescription` | `text` (default), `html` or `none` (structured fields only). Same price. |
| `maxJobsPerCompany` | Save at most N jobs per company. Leave empty for all. |
| `includeCompanyRows` | Put the free company status rows in the dataset (default) or only in the `COMPANIES` record. |
| `maxConcurrency` | Companies processed in parallel (1–10). |
| `failOnErrors` | Mark the run failed if a board can't be fetched or a board URL no longer exists (for schedules). |

Example:

```json
{
  "companies": ["https://job-boards.greenhouse.io/tubitv", "https://jobs.lever.co/genbio", "flowx.ai"],
  "onlyWithSalary": true,
  "includeDescription": "none"
}
```

### Output example

The **Jobs** view on the Output tab gives one line per job, salary first:

![Jobs view in Apify Console: job title, company, salary min and max, currency, period, location, country, workplace, type and hiring system](https://raw.githubusercontent.com/leewilliam200/meridianlabs-apify-assets/main/greenhouse-lever-ashby-jobs-scraper/greenhouse-lever-ashby-jobs-normalised-salary-table.png)

A job row (description shortened):

```json
{
  "record_type": "job",
  "id": "greenhouse:tubitv:8099700",
  "company": "Tubi",
  "system": "greenhouse",
  "board_url": "https://job-boards.greenhouse.io/tubitv",
  "title": "Associate, Content Valuation",
  "department": "Content",
  "location": "Los Angeles, CA (Hybrid)",
  "country": "US",
  "remote": false,
  "workplace": "hybrid",
  "posted_at": "2026-07-31T18:25:29Z",
  "url": "https://job-boards.greenhouse.io/tubitv/jobs/8099700",
  "salary": {
    "min": 59500, "max": 85000, "currency": "USD", "period": "year",
    "source": "ats_field", "raw_text": "$59,500 — $85,000 USD",
    "basis": null, "suspect": false, "eu_pay_range": false, "tiers": []
  },
  "language": "en",
  "change_status": null,
  "fetched_at": "2026-09-25T09:39:10Z",
  "source_url": "https://boards-api.greenhouse.io/v1/boards/tubitv/jobs?content=true",
  "description_text": "About the Role:\n\nTubi is seeking a highly analytical and commercially minded Associate…"
}
```

A multi-zone salary:

```json
"salary": {
  "min": 151800, "max": 178400, "currency": "USD", "period": "year", "source": "ats_field", "basis": "base",
  "tiers": [
    {"label": "Zone 1", "min": 151800, "max": 178400, "currency": "USD", "period": "year"},
    {"label": "Zone 2", "min": 136700, "max": 160600, "currency": "USD", "period": "year"},
    {"label": "Zone 3", "min": 121500, "max": 142700, "currency": "USD", "period": "year"},
    {"label": "Zone 4", "min": 106300, "max": 124900, "currency": "USD", "period": "year"}
  ]
}
```

A company status row (free):

```json
{
  "record_type": "company",
  "input": "https://nvidia.wd5.myworkdayjobs.com/NVIDIAExternalCareerSite",
  "status": "not_supported",
  "reason": "The board URL is on Workday. Workday is not supported: Workday has no public job-board API we can use under its terms. Supported: Greenhouse, Lever, Ashby, Workable, Recruitee and Teamtailor.",
  "jobs_saved": 0,
  "jobs_charged": 0,
  "charged": false
}
```

Job rows and company rows share one dataset; filter on `record_type = "job"` for jobs only, or switch off `includeCompanyRows`.

### Personal data

Job ads sometimes include a recruiter's own email address or phone number. This Actor:

- replaces personal-looking email addresses with `[email removed]` and phone numbers with `[phone removed]`, in both text and HTML descriptions and in salary text;
- keeps role mailboxes (careers@, recruiting@, jobs@, accommodations@, and their Dutch, German, Polish, French and Nordic equivalents), because they're how candidates apply;
- never outputs Recruitee's per-job `mailbox_email` field;
- does **not** remove people's names written in the ad text (e.g. "contact Maria"). Use `includeDescription: none` for structured fields only.

None of the six endpoints exposes recruiter or hiring-manager contact fields, and this Actor doesn't try to find any.

### How do I get a daily feed of new jobs?

1. Paste the companies, add your filters, set **Mode** to **Monitor: only new or changed jobs since the last run** (`newSinceLastRun`) and click **Save as a new task**.
2. Open **Schedules** → **Create new**, pick the task and choose **daily**.
3. The first run returns every open job; after that, each run returns only jobs that are **new or changed**, plus free `closed` notices. Unchanged jobs cost nothing.

Only want the last 24 hours? Set **Posted within the last N days** to `1`. A daily monitor on 100 companies that finds 50 new or changed jobs a day costs about **$0.10 a day**.

### How do I send jobs to Google Sheets, Make, Zapier, n8n or an AI agent?

- **Google Sheets and Drive:** on the Actor's or task's **Integrations** tab, add the Google Drive integration, or use Make, Zapier or n8n (below) with a Google Sheets "add rows" step.
- **Make, Zapier and n8n:** each has an official Apify app or node. Trigger on "Actor run finished", then get the dataset items. Ask for the `jobs` view to get one line per job with the salary columns.
- **Webhooks:** Integrations → **HTTP webhook** on "Run succeeded" sends the run details to your URL.
- **AI agents (MCP):** add `https://mcp.apify.com?actors=meridianlabs/greenhouse-lever-ashby-jobs-scraper` to your MCP client (Claude, Cursor, VS Code and others). The agent can then pull a company's open jobs and salaries.

Python (`pip install apify-client`):

```python
from apify_client import ApifyClient

client = ApifyClient("<YOUR_APIFY_TOKEN>")
run = client.actor("meridianlabs/greenhouse-lever-ashby-jobs-scraper").call(run_input={
    "companies": ["https://job-boards.greenhouse.io/tubitv", "https://jobs.ashbyhq.com/revenuecat"],
    "onlyWithSalary": True,
})
for row in client.dataset(run.default_dataset_id).iterate_items():
    if row["record_type"] == "job":
        s = row["salary"]
        print(row["company"], row["title"], s["min"], s["max"], s["currency"], s["period"])
```

For a daily feed, run it as a scheduled task in monitor mode (see *How do I get a daily feed of new jobs?*).

### Limitations

- **Six hiring systems only.** Companies on Workday, iCIMS, SmartRecruiters, Personio and others get a free `not_supported` row, not jobs.
- **You bring the companies.** This is a live fetch of the companies you list, not a keyword search across every company on the internet.
- **Detection from a name is weaker** than from a URL or domain (38 of 50 in our test, against 47 of 50 from the domain). Careers pages built entirely in JavaScript may hide the board; paste the board URL for those.
- **Salary is only as good as what the employer publishes.** Most jobs outside pay-transparency regions show none. Amounts are never guessed; suspicious entries are flagged, not changed.
- Teamtailor's feed doesn't give an employment type, and Workable's doesn't give an updated date.

### FAQ

#### Is it legal to scrape Greenhouse, Lever or Ashby jobs?

This Actor reads the public job-board endpoints the hiring systems publish so that anyone can list a company's open jobs (Greenhouse, for example, documents that "Job Board data is publicly available, so authentication is not required"). It doesn't log in, use keys or get around robots.txt or bot checks, and it asks for each board once per run. The job ads belong to the employers; use the data in line with the laws that apply to you, especially if you republish ads. Not affiliated with or endorsed by Greenhouse, Lever, Ashby, Workable, Recruitee or Teamtailor.

#### How do I find a company's job-board URL?

Open the company's careers page and click through to a job: the address usually shows the system (`jobs.lever.co/…`, `job-boards.greenhouse.io/…`, `jobs.ashbyhq.com/…`). Or just paste the company's domain and let the Actor find it.

#### Why did a company come back "not\_found"?

Nothing on its careers pages pointed to a supported board, and no board on the six systems matched its name. Common causes: the company uses an unsupported system hidden behind a JavaScript careers page, or no system at all. The `reason` says what was tried. Paste the board URL if you know it.

#### Does monitor mode charge for jobs I've already received?

No. Unchanged jobs are skipped and free. A job counts as changed when its title, location, department, employment type, workplace, pay, apply link or description changes. Closed jobs come back as free `change_status: "closed"` rows.

#### What happens if a run times out or restarts?

Companies that are finished are not fetched or charged again after a restart. When the time limit is near, the remaining companies get free `skipped` rows and the run still ends as succeeded.

### More from Meridian Labs

- **[Google Trends Scraper & API](https://apify.com/meridianlabs/google-trends-scraper)**: Google Trends for hundreds of keywords at once, with a plain-English summary per keyword (rising or falling, year on year, peak, seasonality). $5 per 1,000 keyword lookups.
- **[Keyword Search Volume + Google Trends](https://apify.com/meridianlabs/keyword-search-volume)**: monthly search volume, CPC, competition and keyword difficulty (Google Ads figures) plus a Google Trends summary for every keyword. From $3 per 1,000 keywords.

### Support

Found a board that doesn't parse right, or a salary format it misses? Open an issue on the **Issues** tab with the board URL. We read every one.

If this saved you time, a rating helps others find it; if something's off, open an issue and we'll fix it fast.

# Actor input Schema

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

One per line: a job-board URL (https://jobs.lever.co/company), a careers page URL, a domain (company.com) or a company name. The hiring system is detected automatically. Every company gets a free status row saying what was found; companies on unsupported systems (Workday, iCIMS, ...) are reported, never charged.

## `systems` (type: `array`):

Leave empty for all six. Companies on other systems get a free 'not\_supported' status row.

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

Keep only jobs whose title contains one of these words or phrases (whole words, case-insensitive), e.g. engineer, product manager. Filters apply after the board is fetched; only saved jobs are charged.

## `excludeTitleKeywords` (type: `array`):

Drop jobs whose title contains any of these, e.g. intern, senior.

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

Keep jobs whose location, city or region contains one of these, or whose country code matches a 2-letter code, e.g. US, Germany, London, Remote.

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

Keep only jobs the hiring system marks (or the location states) as fully remote. Hybrid jobs are not remote.

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

Keep only jobs first published in the last N days. Jobs without a publish date are dropped when this is set.

## `onlyWithSalary` (type: `boolean`):

Keep only jobs with a salary (from the hiring system's pay field or the ad text).

## `mode` (type: `string`):

Monitor mode remembers which jobs it delivered (stable IDs in a named key-value store in your account) and saves, and charges, only jobs that are new or changed since the last run, plus free 'closed' notices for jobs that disappeared. The first monitor run sees every job as new. Schedule it daily for a hiring-signal feed.

## `monitorName` (type: `string`):

Only used in monitor mode. Runs with the same name share one memory of delivered jobs; use a different name for each separate watch list (letters, digits, hyphens).

## `includeDescription` (type: `string`):

Personal email addresses and phone numbers are removed from descriptions either way. 'None' gives structured fields only (title, location, salary...). Same price.

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

Save at most this many jobs per company (after filters). Leave empty for all. A simple way to cap cost.

## `includeCompanyRows` (type: `boolean`):

On: one free row per company (record\_type 'company') alongside the job rows. Off: the dataset holds job rows only; the status rows are still saved in the run's key-value store as COMPANIES.

## `maxConcurrency` (type: `integer`):

How many companies to work on at once. Requests to the same hiring system are always spaced out politely (robots.txt and crawl delays are obeyed), so more parallelism mostly helps mixed lists.

## `failOnErrors` (type: `boolean`):

Useful for schedules: the run is marked failed (so Apify can alert you) if a board could not be fetched, or a board URL you gave no longer exists. Failed companies are never charged.

## Actor input object example

```json
{
  "companies": [
    "https://job-boards.greenhouse.io/tubitv",
    "https://jobs.lever.co/genbio",
    "https://jobs.ashbyhq.com/revenuecat",
    "https://qualifyzegmbh.recruitee.com/",
    "https://ube-careers.teamtailor.com/jobs",
    "flowx.ai",
    "https://nvidia.wd5.myworkdayjobs.com/NVIDIAExternalCareerSite"
  ],
  "remoteOnly": false,
  "onlyWithSalary": false,
  "mode": "all",
  "monitorName": "default",
  "includeDescription": "text",
  "maxJobsPerCompany": 10,
  "includeCompanyRows": true,
  "maxConcurrency": 5,
  "failOnErrors": false
}
```

# Actor output Schema

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

Job rows with the normalised salary (dataset view 'jobs'). Company status rows, if included, show here with empty job columns; filter on record\_type = job.

## `companies` (type: `string`):

One row per company: resolved, not\_supported or not\_found, with the reason and job counts.

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

Every row and field, including descriptions and salary tiers.

# 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://job-boards.greenhouse.io/tubitv",
        "https://jobs.lever.co/genbio",
        "https://jobs.ashbyhq.com/revenuecat",
        "https://qualifyzegmbh.recruitee.com/",
        "https://ube-careers.teamtailor.com/jobs",
        "flowx.ai",
        "https://nvidia.wd5.myworkdayjobs.com/NVIDIAExternalCareerSite"
    ],
    "maxJobsPerCompany": 10
};

// Run the Actor and wait for it to finish
const run = await client.actor("meridianlabs/greenhouse-lever-ashby-jobs-scraper").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://job-boards.greenhouse.io/tubitv",
        "https://jobs.lever.co/genbio",
        "https://jobs.ashbyhq.com/revenuecat",
        "https://qualifyzegmbh.recruitee.com/",
        "https://ube-careers.teamtailor.com/jobs",
        "flowx.ai",
        "https://nvidia.wd5.myworkdayjobs.com/NVIDIAExternalCareerSite",
    ],
    "maxJobsPerCompany": 10,
}

# Run the Actor and wait for it to finish
run = client.actor("meridianlabs/greenhouse-lever-ashby-jobs-scraper").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://job-boards.greenhouse.io/tubitv",
    "https://jobs.lever.co/genbio",
    "https://jobs.ashbyhq.com/revenuecat",
    "https://qualifyzegmbh.recruitee.com/",
    "https://ube-careers.teamtailor.com/jobs",
    "flowx.ai",
    "https://nvidia.wd5.myworkdayjobs.com/NVIDIAExternalCareerSite"
  ],
  "maxJobsPerCompany": 10
}' |
apify call meridianlabs/greenhouse-lever-ashby-jobs-scraper --silent --output-dataset

```

## MCP server setup

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

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/RXyqs5U2sbPN32uNg/builds/AcTeDQ0k5zxabt7AV/openapi.json
