# ATS Jobs Scraper: Greenhouse, Lever, Ashby, Workday & more (`lanternlane-data/careers-page-jobs-aggregator`) Actor

Scrape every open job from company career pages on Greenhouse, Lever, Ashby, Workday, SmartRecruiters, Workable and Recruitee. Paste company names or URLs, the ATS is auto-detected, and you get one clean schema with salary, remote flag and full description, plus new and closed job alerts.

- **URL**: https://apify.com/lanternlane-data/careers-page-jobs-aggregator.md
- **Developed by:** [Lantern Lane Data](https://apify.com/lanternlane-data) (community)
- **Categories:** Jobs, Lead generation, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $3.00 / 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.

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

## ATS Jobs Scraper: Greenhouse, Lever, Ashby, Workday, SmartRecruiters, Workable & Recruitee

### 💼 What is the ATS Jobs Scraper?

Get **every open job from company career pages** in one clean, normalised dataset. Paste a list of companies (names, website domains or job-board URLs) and this Actor **auto-detects which applicant tracking system (ATS) each company uses**, reads the ATS's public job-board feed and returns one consistent schema with title, locations, remote/hybrid flag, department, employment type, **salary when published**, full description (text + HTML), apply link and posted date.

Run it on a schedule and it also tells you **which jobs are new and which were closed since the last run**, which makes it a ready-made job monitoring, hiring-signal and lead-generation feed.

- ✅ 7 ATS platforms: **Greenhouse, Lever, Ashby, Workday, SmartRecruiters, Workable, Recruitee**
- ✅ Auto-detects the ATS and board slug from a company name, domain or careers-page URL
- ✅ One normalised schema for all sources (no per-ATS parsing on your side)
- ✅ Salary ranges from structured ATS data, or parsed from the job text when the employer publishes a range
- ✅ New / closed job flags between runs (change tracking)
- ✅ Filters: keywords, locations, remote / hybrid / on-site, departments, employment type, posted since
- ✅ **NEW: optional AI enrichment** tags every job with seniority, remote / hybrid / on-site, job function and tech stack (no extra charge)
- ✅ Recruiter personal names, personal e-mails and phone numbers removed
- ✅ No login, no browser, no captcha solving: only the official public job-board endpoints, with polite rate limiting
- ✅ Pay only for jobs you get: **$3 per 1,000 jobs**

### 🎯 What can I use it for?

- **Job boards & aggregators**: fill a niche job board (remote jobs, AI jobs, jobs in Berlin, ...) straight from employers' own career sites, with apply links that go to the source.
- **Hiring signals & sales intelligence**: see which companies are hiring for what (e.g. "who opened Data Engineering roles this week?") and trigger outreach.
- **Recruiting & sourcing**: monitor competitor and target-company openings, salary bands and new teams.
- **Market & salary research**: build datasets of roles, locations and published pay ranges across hundreds of companies.
- **Job seekers & career tools**: get alerted when a company you like posts a job that matches your keywords.
- **AI agents**: a predictable, schema-documented output that agents can call through the Apify API or MCP.

### 🧩 Supported applicant tracking systems

| ATS | Example input | How it's read | Description | Salary |
|---|---|---|---|---|
| Greenhouse | `https://boards.greenhouse.io/airbnb`, `Stripe` | Job Board API | ✅ | parsed from text, or structured when published |
| Lever (US & EU) | `https://jobs.lever.co/palantir`, `spotify` | Postings API | ✅ | ✅ structured `salaryRange` when published, else parsed from text |
| Ashby | `https://jobs.ashbyhq.com/openai`, `notion.so` | Job Posting API | ✅ | ✅ structured compensation |
| Workday | `https://nvidia.wd5.myworkdayjobs.com/NVIDIAExternalCareerSite`, `intel.com` | Career-site JSON | ✅ (1 request per job) | parsed from text |
| SmartRecruiters | `https://jobs.smartrecruiters.com/ServiceNow`, `ServiceNow` | Posting API | ✅ (1 request per job) | parsed from text |
| Workable | `https://apply.workable.com/huggingface/` | Public widget API | ✅ | parsed from text |
| Recruitee | `https://bunq.recruitee.com`, `bunq` | Careers Site API | ✅ | ✅ structured when published |

**Auto-detection.** For each input the Actor (1) reads a job-board URL directly, (2) for a domain or careers-page URL, fetches the careers pages and looks for ATS links/embeds, and (3) for a plain name, checks the likely board slug on each ATS and picks the board with the most jobs. If you already know the ATS you can force it, e.g. `greenhouse:airbnb`, `lever:palantir`, `ashby:openai`, `smartrecruiters:ServiceNow`, `workable:huggingface`, `recruitee:bunq`, `workday:intel.wd1/External`.

Tip: job-board URLs are the most precise input. A name like `Linear` is matched to the board called `linear`, which is usually, but not always, the company you mean. Check the `company` and `boardUrl` fields, or the run summary.

### ⬇️ Input

| Field | Description |
|---|---|
| `companies` (required) | Company names, domains, careers-page URLs or job-board URLs, one per line. |
| `keywords` | Keep jobs whose title contains any of these words (whole-word, case-insensitive). |
| `searchInDescription` | Also match keywords in department and description. |
| `excludeKeywords` | Drop jobs whose title contains any of these words. |
| `locations` | Keep jobs whose location or country contains any of these strings. `Remote` also keeps all remote jobs. |
| `workplace` | `any`, `remote`, `remoteOrHybrid` or `onsite`. |
| `departments` | Keep jobs whose department or team contains any of these strings. |
| `employmentTypes` | `full-time`, `part-time`, `contract`, `internship`, `temporary`, `volunteer`, `other`. |
| `postedSince` | `2026-09-01` or relative: `7 days`, `2 weeks`, `1 month`. |
| `maxJobs` | Total cap on job records (default 1,000; `0` = no limit). Also caps your cost. |
| `maxJobsPerCompany` | Cap per job board (`0` = no limit). |
| `includeDescription` | Return full description text + HTML (default on). Turning it off makes Workday and SmartRecruiters boards much faster. |
| `enrichWithAI` | Add `aiSeniority`, `aiWorkplace`, `aiJobFunction`, `aiConfidence` and `techStack` to every job (default off, no extra charge). |
| `trackChanges` | Remember each board's jobs between runs and set `isNew` / `firstSeenAt` (default on). |
| `onlyNewJobs` | Output only jobs that weren't open on the previous run. |
| `includeClosedJobs` | Also output a short `status: "closed"` record for jobs removed since the previous run. |
| `stateStoreName` | Name of the key-value store that keeps tracking state; use different names for separate monitors. |
| `maxConcurrency` | Boards fetched in parallel (default 5). Requests per host are rate-limited regardless. |
| `proxyConfiguration` | Optional. Not needed for most boards; useful if a board rate-limits you. |

#### Example input

```json
{
  "companies": [
    "https://boards.greenhouse.io/airbnb",
    "Stripe",
    "https://jobs.lever.co/palantir",
    "OpenAI",
    "https://nvidia.wd5.myworkdayjobs.com/NVIDIAExternalCareerSite",
    "https://jobs.smartrecruiters.com/ServiceNow",
    "https://apply.workable.com/huggingface/",
    "https://bunq.recruitee.com"
  ],
  "keywords": ["engineer", "data scientist"],
  "workplace": "remoteOrHybrid",
  "postedSince": "14 days",
  "maxJobs": 500
}
```

#### Daily "new jobs only" monitor

Create a task with your company list and `"onlyNewJobs": true`, optionally `"includeClosedJobs": true`, and schedule it daily. The first run returns everything that matches (everything is new on the first run). From then on each run returns only jobs that appeared since the previous run, plus closed-job records if you asked for them. Connect a webhook, Slack, Google Sheets, Zapier or Make integration to get alerts.

### ⬆️ Output

One record per job. Abridged example (see `sample_output.json` for one record from every ATS):

```json
{
  "id": "ashby-openai-8fb1615c-34bf-47c4-a1d1-b7b2f836bbd3",
  "atsJobId": "8fb1615c-34bf-47c4-a1d1-b7b2f836bbd3",
  "ats": "ashby",
  "company": "OpenAI",
  "companySlug": "openai",
  "title": "Technical Program Manager, Compute Infrastructure",
  "location": "San Francisco",
  "locations": ["San Francisco"],
  "country": "United States",
  "isRemote": false,
  "workplaceType": null,
  "department": "Technical Program Management",
  "team": null,
  "employmentType": "full-time",
  "employmentTypeRaw": "FullTime",
  "salary": { "min": 257000, "max": 335000, "currency": "USD", "interval": "year", "text": "$257K – $335K • Offers Equity", "source": "ats" },
  "descriptionText": "About the Team\n\nThe compute infrastructure team runs the GPU fleet ...",
  "descriptionHtml": "<h3><strong>About the Team</strong></h3><p>The compute infrastructure team ...",
  "applyUrl": "https://jobs.ashbyhq.com/openai/8fb1615c-.../application",
  "jobUrl": "https://jobs.ashbyhq.com/openai/8fb1615c-...",
  "postedAt": "2026-03-12T16:38:15.322000Z",
  "updatedAt": null,
  "postedAtIsApproximate": false,
  "requisitionId": null,
  "experienceLevel": null,
  "boardUrl": "https://jobs.ashbyhq.com/openai",
  "status": "open",
  "isNew": true,
  "firstSeenAt": "2026-10-08T06:12:22Z",
  "lastSeenAt": "2026-10-08T06:12:22Z",
  "closedAt": null,
  "input": "OpenAI",
  "scrapedAt": "2026-10-08T06:12:22Z"
}
```

Key fields:

- `id`: stable across runs (`<ats>-<board>-<atsJobId>`), safe to use as a primary key. Jobs are de-duplicated by it.
- `salary.source`: `ats` when the employer published a structured range in the ATS, `description` when a range like `$150,000 - $200,000` was found in the job text. `null` when no pay was published.
- `workplaceType` / `isRemote`: from the ATS's own remote/hybrid fields when available; otherwise from the location text or an explicit "work model" statement in the description.
- `postedAt`: ISO-8601 UTC. Workday only shows "Posted 3 Days Ago" in listings; with descriptions on, the exact start date is used, otherwise `postedAtIsApproximate` is `true`.
- `isNew`, `firstSeenAt`, `lastSeenAt`, `status`, `closedAt`: change tracking (see above).

#### 🤖 AI enrichment (`enrichWithAI: true`)

Turn it on and every job also gets:

| Field | Values |
|---|---|
| `aiSeniority` | `intern`, `entry`, `mid`, `senior`, `lead_manager`, `director`, `executive` |
| `aiWorkplace` | `remote`, `hybrid`, `onsite` |
| `aiJobFunction` | `engineering`, `data_science`, `product`, `design`, `sales`, `marketing`, `customer_success`, `operations`, `finance`, `people`, `it_security`, `other` |
| `aiConfidence` | 0–1 confidence for each of the three fields above |
| `techStack` | Technologies named in the posting, e.g. `["Python", "React", "AWS", "Kubernetes"]` |

When the model isn't confident (below 0.5), the field is `unknown` rather than a guess. Filter on `aiSeniority = "senior"` and `aiJobFunction = "engineering"` to get a clean senior-engineer feed, or count `techStack` across a company's openings to see what it's building.

```json
"aiSeniority": "senior", "aiWorkplace": "remote", "aiJobFunction": "engineering",
"aiConfidence": {"seniority": 0.97, "workplace": 0.88, "function": 0.99},
"techStack": ["PostgreSQL", "Kubernetes", "Rust"]
```

The dataset has three views in Apify Console: **Overview**, **Salary** and **New & closed**. Download it as JSON, CSV, Excel, XML or RSS, or read it through the API. Each run also saves a `RUN_SUMMARY` record in the key-value store with the detected ATS, board URL, job counts and any errors for every input.

### 💰 How much does it cost?

**Free until 22 October 2026.** After that:

This Actor uses **pay-per-event** pricing: you pay for results, not for compute time.

| Event | Price |
|---|---|
| Job record in the dataset (`job-result`) | **$0.003** ($3 per 1,000 jobs) |
| Actor start | $0.00005 per run (Apify's standard start fee) |

Examples: 200 jobs ≈ $0.60, 1,000 jobs ≈ $3, a daily "new jobs only" monitor over 100 companies returning about 150 new jobs per day ≈ $0.45 per day. Inputs that can't be detected or fetched are **not charged**. Use `maxJobs` or the run's maximum cost setting to cap spending: the Actor stops cleanly when your limit is reached.

### ❓ FAQ

**Does AI enrichment cost extra?** No. It's included in the per-job price. It's a classification step, so it adds about a second per job to the run.

**Do I need an account with any of these ATS vendors?** No. The Actor uses the public endpoints that power each company's own careers page. No login, cookies or API keys.

**Why didn't my company get detected?** Some companies use an ATS that isn't supported (for example a custom site, iCIMS, Taleo or SuccessFactors), or their careers page is fully JavaScript-rendered so the ATS link isn't in the HTML. Paste the job-board URL from any "Apply" link instead, e.g. `https://<company>.wd5.myworkdayjobs.com/<site>`. The run summary lists every input that couldn't be resolved, and you aren't charged for it.

**How fresh is the data?** Live: every run reads the boards at that moment.

**How many companies can I add?** Hundreds per run. Boards are fetched in parallel (`maxConcurrency`) with per-host rate limits so the sources aren't overloaded.

**Why is Workday slower?** Workday lists 20 jobs per page and needs one request per job for the description. Use `maxJobsPerCompany`, filters (they're applied before the per-job request where possible) or `includeDescription: false` for speed. Boards with more than 2,000 jobs are split by category automatically to work around Workday's 2,000-result limit.

**Are recruiter names and e-mails removed?** Yes. Personal e-mail addresses, phone numbers, "Recruiter: Jane Doe"-style lines and names next to removed contact details are removed from descriptions. Generic company mailboxes (careers@, accommodations@) are kept because candidates need them. Per-recruiter fields that some ATSes expose (e.g. the posting creator or internal application mailboxes) are never output.

**Is "new" based on my filters?** No. Change tracking is per board: a job is new the first time the Actor sees it open on that board. Jobs that matched your filters but weren't delivered because of `maxJobs` stay "new" for the next run. Closed-job detection needs the full board listing, so it's skipped for a board in runs where `maxJobs` or `maxJobsPerCompany` stopped that board early.

**Can I use it from code?** Yes. Use the Apify API, the Python or JavaScript `apify-client`, or MCP. Example with Python:

```python
from apify_client import ApifyClient
client = ApifyClient("<YOUR_APIFY_TOKEN>")
run = client.actor("lanternlane-data/careers-page-jobs-aggregator").call(run_input={"companies": ["stripe", "openai"], "keywords": ["engineer"]})
for job in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(job["company"], job["title"], job["jobUrl"])
```

### ⚠️ Limitations

- Only the 7 ATS platforms above. Custom careers sites and other ATSes aren't scraped.
- Name-based detection guesses the board slug; prefer job-board URLs for precision.
- Workday tenants that hide jobs behind login or captcha aren't supported.
- Salary parsing from description text is best-effort; check `salary.text` and `salary.source`.
- Some providers (e.g. Workable) rate-limit by IP address. If a board fails with HTTP 429, enable Apify Proxy in `proxyConfiguration` or run again later.

### ⚖️ Is it legal?

This Actor only reads **publicly available job postings** from the JSON endpoints that employers' own careers pages use to show their jobs. It doesn't log in, bypass captchas or access anything behind authentication, and it rate-limits its requests. Job postings are published by employers so that they reach as many candidates as possible; personal data of recruiters is stripped from the output.

You're still responsible for how you use the data: comply with the terms of the sites involved, copyright in job descriptions, and data-protection laws such as GDPR (for example, if you republish postings or combine them with personal data). If in doubt, consult a lawyer. This Actor isn't affiliated with or endorsed by Greenhouse, Lever, Ashby, Workday, SmartRecruiters, Workable or Recruitee; their names are trademarks of their respective owners.

### 💬 Support

Found a board that doesn't work, or need another ATS? Open an issue on the Actor's **Issues** tab with the board URL and we'll take a look.

### 🏮 More from Lantern Lane Data

**Jobs & hiring data** is our focus: job postings straight from employers' applicant tracking systems and official public feeds, in one consistent schema. More ATS platforms and hiring-signal tools are on the way.

- 🌍 [Remote Jobs Scraper](https://apify.com/lanternlane-data/remote-jobs-aggregator): Remote jobs from 7 boards via their official public feeds, deduplicated, with salary and location filters.

**Other tools**

- 🛍️ [Shopify Products Scraper](https://apify.com/lanternlane-data/shopify-store-products-scraper): Every product, price, variant and stock level from any Shopify store, with price-change tracking.
- 🗺️ [Sitemap URL Extractor](https://apify.com/lanternlane-data/sitemap-url-extractor): Every URL from any website's XML sitemaps, with lastmod, hreflang and new-page alerts.
- 🔦 [AI Brand Visibility Tracker](https://apify.com/lanternlane-data/ai-brand-visibility-tracker): How often ChatGPT, Perplexity, Gemini and Claude mention, rank and cite your brand vs competitors.

***

Built and maintained by **Lantern Lane Data**.

# Changelog

This Actor's version history is a separate document: https://apify.com/lanternlane-data/careers-page-jobs-aggregator/changelog.md

# Actor input Schema

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

One per line. Accepts a company name (<code>Stripe</code>), a website domain (<code>notion.so</code>), a careers page URL, or a job-board URL (<code>https://jobs.lever.co/palantir</code>, <code>https://nvidia.wd5.myworkdayjobs.com/NVIDIAExternalCareerSite</code>). The ATS and board slug are detected automatically. To force one, prefix it: <code>greenhouse:airbnb</code>, <code>lever:palantir</code>, <code>ashby:openai</code>, <code>smartrecruiters:ServiceNow</code>, <code>workable:huggingface</code>, <code>recruitee:bunq</code>, <code>workday:intel.wd1/External</code>.

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

Keep jobs whose title contains at least one of these words or phrases (case-insensitive, whole words). Leave empty for all jobs.

## `searchInDescription` (type: `boolean`):

By default keywords are matched against the job title only. Enable to also search department and full description text.

## `excludeKeywords` (type: `array`):

Drop jobs whose title contains any of these words, e.g. <code>intern</code>, <code>senior</code>.

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

Keep jobs whose location or country contains one of these strings, e.g. <code>London</code>, <code>Germany</code>, <code>US</code>. Adding <code>Remote</code> also keeps all remote jobs.

## `workplace` (type: `string`):

Filter by remote / hybrid / on-site, based on the ATS's own flag when published and on the location text otherwise.

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

Keep jobs whose department or team contains one of these strings, e.g. <code>Engineering</code>, <code>Sales</code>.

## `employmentTypes` (type: `array`):

Keep only these normalised employment types. Leave empty for all.

## `postedSince` (type: `string`):

Keep jobs first published on or after this date. Absolute (<code>2026-09-01</code>) or relative (<code>7 days</code>, <code>2 weeks</code>, <code>1 month</code>).

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

Stop after this many job records across all companies. 0 = no limit. You are charged per job record, so this also caps the cost of a run.

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

Cap per job board. 0 = no limit.

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

Return description text and HTML. Workday and SmartRecruiters need one extra request per job for this; turning it off makes those boards much faster (but Workday then gives fewer location details).

## `enrichWithAI` (type: `boolean`):

Tag every job with <code>aiSeniority</code> (intern / entry / mid / senior / lead_manager / director / executive), <code>aiWorkplace</code> (remote / hybrid / onsite), <code>aiJobFunction</code> (engineering, sales, product, ...) and <code>techStack</code> (Python, React, AWS, Kubernetes, ...). Low-confidence answers come back as <code>unknown</code> instead of a guess. No extra charge.

## `trackChanges` (type: `boolean`):

Remember which jobs each board had on the previous run (in a named key-value store) and set <code>isNew</code> / <code>firstSeenAt</code> on every job. Ideal for scheduled runs.

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

Only output jobs that were not open on the previous run (all jobs are new on the first run). Requires change tracking.

## `includeClosedJobs` (type: `boolean`):

Also output a short record (<code>status: "closed"</code>) for each job that was open on the previous run but has since been removed. Requires change tracking.

## `stateStoreName` (type: `string`):

Name of the key-value store that keeps change-tracking state. Use different names to keep separate monitors (e.g. one per client).

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

How many job boards to fetch at the same time. Requests to each host are additionally rate-limited.

## `proxyConfiguration` (type: `object`):

Not needed for most boards. Use Apify Proxy if a board (e.g. Workable) rate-limits your requests.

## Actor input object example

```json
{
  "companies": [
    "stripe",
    "notion.so",
    "https://jobs.lever.co/palantir",
    "https://nvidia.wd5.myworkdayjobs.com/NVIDIAExternalCareerSite"
  ],
  "searchInDescription": false,
  "workplace": "any",
  "maxJobs": 1000,
  "maxJobsPerCompany": 0,
  "includeDescription": true,
  "enrichWithAI": false,
  "trackChanges": true,
  "onlyNewJobs": false,
  "includeClosedJobs": false,
  "stateStoreName": "careers-job-tracker",
  "maxConcurrency": 5,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

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

One normalised record per job posting (open, or closed when 'Output closed jobs' is on).

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

Per-input detection result (ATS, board slug), job counts, new/closed counts and errors.

# 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",
        "openai",
        "https://adobe.wd5.myworkdayjobs.com/external_experienced"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("lanternlane-data/careers-page-jobs-aggregator").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",
        "openai",
        "https://adobe.wd5.myworkdayjobs.com/external_experienced",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("lanternlane-data/careers-page-jobs-aggregator").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",
    "openai",
    "https://adobe.wd5.myworkdayjobs.com/external_experienced"
  ]
}' |
apify call lanternlane-data/careers-page-jobs-aggregator --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,lanternlane-data/careers-page-jobs-aggregator"
        }
    }
}
```

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/eiVHlHweTC8jSsiEU/builds/GUVsVX5Z0f2LdUpP0/openapi.json
