# Greenhouse, Lever, Ashby & Personio Jobs Feed (`leonardoo/multi-ats-company-jobs-feed`) Actor

Get every open job from any company's careers page in one clean format. Paste careers URLs or company names: it finds the Greenhouse, Lever, Ashby or Personio board and pulls jobs from the official public APIs. Filters, salaries, only-new-jobs mode. Recruiter contacts removed.

- **URL**: https://apify.com/leonardoo/multi-ats-company-jobs-feed.md
- **Developed by:** [Clean Data Feeds](https://apify.com/leonardoo) (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 $1.20 / 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

### What is Greenhouse, Lever, Ashby & Personio Jobs Feed?

**Greenhouse, Lever, Ashby & Personio Jobs Feed** collects **every open job from a list of companies** and returns them in **one clean, consistent format**. Paste careers-page URLs, job-board links or just company names. The Actor finds each company's applicant tracking system (ATS), pulls the jobs from the **official public job-board APIs**, and can return **only jobs that are new since your last run**.

Use it as a **jobs API for company career pages**: no browser, no proxies, no login, and no stitching together five different job-board formats.

🔒 **Personal data is removed by default.** Recruiter emails, phone numbers and "Recruiter: Jane Doe" style names are stripped from job descriptions, and no recruiter or job-creator fields are output.

### Why use it?

- 🧭 **Auto-detects the job board.** Give it `https://www.example.com/careers`, `https://jobs.lever.co/spotify` or simply `Linear` and it finds the right Greenhouse, Lever, Ashby or Personio board.
- 🧩 **One schema for all ATS.** Title, department, team, locations, remote flag, employment type, posting date, pay range, apply link and clean description text, the same way for every company.
- 🔔 **Only-new-jobs mode.** Schedule it daily and get just the jobs posted since the last run: ideal for alerts, job boards and hiring-signal feeds.
- 💵 **Salary ranges** when the company publishes them (Ashby and Lever).
- ✅ **Official, public endpoints only.** Greenhouse Job Board API, Lever Postings API (with Lever's 1-second crawl delay), Ashby Posting API and Personio's public XML feed.
- 🔌 **Works with everything Apify offers:** scheduling, API, webhooks, Zapier, Make, Google Sheets, Slack and AI agents through MCP.

### Who is it for?

- **Recruiting agencies and sourcers** watching target companies for new roles.
- **Job boards and aggregators** that need clean feeds straight from company career sites.
- **Sales and RevOps teams** using "this company is hiring for X" as a buying signal.
- **Investors, market and talent researchers** tracking hiring trends by company, team or location.

### Supported job boards

| ATS | Official source used | Notes |
|---|---|---|
| Greenhouse | Job Board API (`boards-api.greenhouse.io`) | Public, no login |
| Lever | Postings API (`api.lever.co`, plus the EU instance) | Respects Lever's 1-second crawl delay |
| Ashby | Public Posting API (`api.ashbyhq.com/posting-api`) | Includes pay ranges when published |
| Personio | Public XML job feed (`{company}.jobs.personio.de/xml`) | Common for European companies |
| SmartRecruiters (beta, off by default) | Posting API (`api.smartrecruiters.com`) | See "Data sources" before enabling |

### How to use it

1. Click **Try for free** (or **Start** in Apify Console).
2. In **Companies**, add one company per line: a careers-page URL, a job-board URL, an `ats:token` such as `greenhouse:discord`, or a company name.
3. Optionally add **filters**: title keywords, excluded words, locations, remote only, departments, posted in the last N days.
4. Click **Start**. Jobs appear in the **Output** tab, usually within seconds.
5. Download them as **Excel, CSV, JSON, XML or HTML**, or connect them to another app.

Check the **Company detection report** (the `COMPANIES` record in the run's storage) to see which board each input matched, so you can reuse the exact `ats:token` next time.

#### Input example

```json
{
    "companies": [
        "greenhouse:discord",
        "https://jobs.lever.co/spotify",
        "Linear",
        "https://www.example.com/careers",
        "personio:acme"
    ],
    "keywords": ["engineer", "developer"],
    "locations": ["London", "Remote"],
    "onlyNewJobs": true,
    "stateKey": "my-target-companies",
    "includeDescription": true,
    "maxJobsPerCompany": 0
}
```

The default input (Discord, Spotify and Linear, 10 jobs each) finishes in a few seconds.

#### Output example

The **Output** tab shows a table like this (real jobs from October 2026, shortened):

| Company | ATS | Title | Department | Location | Remote | Type | Posted | Pay |
|---|---|---|---|---|---|---|---|---|
| Discord | greenhouse | Commercial Policy Lead | Policy | San Francisco Bay Area | No | – | 2026-09-15 | – |
| Spotify | lever | Android Engineer - Experience Engineering | Engineering | London | No | Permanent | 2026-06-23 | – |
| Linear | ashby | Senior / Staff Fullstack Engineer | Product | Europe | Yes | FullTime | 2021-04-27 | – |
| Ramp | ashby | Security Engineer, Cloud | Engineering | New York, NY (HQ) | Yes | FullTime | 2026-04-07 | $211.4K – $290.6K • Offers Equity |

Each row is a JSON record:

```json
{
    "company": "Discord",
    "companyToken": "discord",
    "ats": "greenhouse",
    "jobId": "8806482002",
    "title": "Commercial Policy Lead",
    "department": "Policy",
    "team": null,
    "locations": ["San Francisco Bay Area", "San Francisco, California, United States"],
    "location": "San Francisco Bay Area",
    "remote": false,
    "workplaceType": null,
    "employmentType": null,
    "postedAt": "2026-09-15T12:52:11-04:00",
    "updatedAt": "2026-09-15T12:52:11-04:00",
    "compensation": null,
    "applyUrl": "https://job-boards.greenhouse.io/discord/jobs/8806482002",
    "jobUrl": "https://job-boards.greenhouse.io/discord/jobs/8806482002",
    "descriptionText": "Discord has a highly engaged community of millions of daily active users...",
    "firstSeenAt": "2026-10-07T05:42:44+00:00",
    "scrapedAt": "2026-10-07T05:42:44+00:00"
}
```

When a company publishes pay, `compensation` looks like `{"summary": "$211.4K – $290.6K • Offers Equity", "min": 211400, "max": 290600, "currency": "USD", "interval": "1 YEAR"}`.

### How much does it cost?

This Actor uses simple **pay-per-event** pricing, so you only pay for what you get:

- **$2.00 per 1,000 jobs** on the Apify free plan ($0.002 per job), and less on paid plans: **$1.80** (Starter), **$1.50** (Scale), **$1.20** (Business) per 1,000.
- **$0.005 per run** start fee.
- No extra charges for platform usage, and company lookups that find no board cost nothing. The **Pricing** tab shows your exact price.

What that means in practice:

- The default test run (30 jobs) costs **about $0.07**.
- A full snapshot of 50 tech companies (about 3,000 open jobs) costs **about $6**.
- Monitoring the same 50 companies daily with "Only new jobs" usually returns 20-150 new jobs a day: **roughly $1.50-9 per month**.
- Apify's free plan includes $5 of monthly credit, enough for about 2,400 jobs.
- Use **Max results** or **Max jobs per company** to cap any run.

### How to get only new jobs every day (scheduling guide)

1. Add your companies and switch on **Only new jobs since last run**.
2. Give the list a **Saved list name**, e.g. `fintech-targets`. Use a different name for each company list.
3. Click **Save as a new task** so the input is stored.
4. Open the task, click **Schedule**, and choose **Daily** (or hourly if you need faster alerts).
5. Connect the results: add a Slack, email, Google Sheets, Zapier or Make integration to the task, or poll the dataset through the API.

The first run returns all current jobs. Every later run returns only jobs that were not output before for that saved list name.

### Integrations and API

- **Apify API:** run the Actor and get results in one call:

```bash
curl -X POST "https://api.apify.com/v2/acts/leonardoo~multi-ats-company-jobs-feed/run-sync-get-dataset-items?token=<YOUR_APIFY_TOKEN>" \
  -H "Content-Type: application/json" \
  -d '{"companies": ["greenhouse:discord", "lever:spotify"], "keywords": ["engineer"]}'
```

- **Python and JavaScript:** use the official `apify-client` packages. See the **API** tab for ready-to-copy code.
- **Zapier and Make:** send new jobs to Google Sheets, Airtable, HubSpot, Salesforce, Slack, Microsoft Teams or email.
- **Webhooks:** get a notification when a run finishes and fetch the new jobs.
- **AI agents (MCP):** add this Actor as a tool in Claude, Cursor or any MCP client with `https://mcp.apify.com?tools=leonardoo/multi-ats-company-jobs-feed`, then ask things like "which of these 20 companies opened new data-engineering roles in Berlin this week?".

### Personal data removed by default

- Email addresses in descriptions are removed, including generic ones such as accommodation or security mailboxes. Follow `jobUrl` for official contact options.
- Phone numbers and phrases such as "Recruiter: Jane Doe", "Contact: ..." or "Ansprechpartnerin: Frau ..." are replaced with `[email removed]`, `[phone removed]` and `[name removed]`.
- No recruiter, hiring-manager or job-creator fields are ever output.
- Removal from free text is best-effort. Switch off **Include description text** for a strict no-names feed.

### Data sources, terms and attribution

- Only official, documented public job-board endpoints are used. Greenhouse states its job-board GET endpoints are public. Lever's API allows access with a 1-second crawl delay, which is enforced. Ashby is accessed only through its documented `api.ashbyhq.com` Posting API. Personio's public XML feed is offered for career-site integrations.
- When a careers-page URL is given, the page is fetched only if the site's robots.txt allows it.
- **SmartRecruiters** documents its Posting API as public for published jobs, but its API robots.txt disallows generic crawlers, so it is **off by default**. Enable it only if you are comfortable with that and only for specific companies.
- Job postings are published by the employers and their text remains theirs. Link back to `jobUrl` when you republish and check each employer's terms.
- Not affiliated with, sponsored or endorsed by Greenhouse, Lever, Ashby, Personio or SmartRecruiters. Their names are used only to describe compatibility.

### Limitations

- Only jobs a company publishes on its public job board are available. Internal or unlisted jobs are not.
- Workday, iCIMS, Taleo and other ATS are not supported.
- Name guessing can match a different company with the same board name. Use a URL or `ats:token` for certainty and check the company detection report.
- Lever and Ashby do not return a company display name, so `company` is derived from the board token (e.g. `ramp` becomes `Ramp`).
- Greenhouse does not expose structured pay ranges in its public list API, so Greenhouse `compensation` is empty.
- Lever is limited to one request per second, so long lists of Lever companies take a little longer.
- "Only new jobs" state is stored in a named key-value store in your account (`ats-jobs-feed-state-<saved list name>`). If you use **Max jobs per company**, jobs not output yet show up in later runs.

### FAQ

#### Which companies are supported?

Any company whose public careers board runs on Greenhouse, Lever, Ashby or Personio (SmartRecruiters optional). Thousands of tech companies and European employers use them.

#### How do I find a company's board token?

Paste its careers-page URL. The company detection report shows the token so you can reuse `ats:token` next time.

#### Can I monitor companies for new jobs?

Yes. Schedule the Actor with **Only new jobs since last run** and a fixed **Saved list name**. Each run returns only new jobs.

#### Is this a Greenhouse API or Lever API alternative?

It uses those official public APIs for you and merges them into one format, so you don't have to write and maintain separate integrations.

#### Do you use proxies or a browser?

No. Plain HTTPS requests to official APIs with a clear User-Agent.

#### Is it legal?

It reads public job postings from official public endpoints that the job-board providers offer for this purpose. You are responsible for how you use the data and for respecting employers' terms when republishing.

#### Something doesn't work. What should I do?

Open an issue in the **Issues** tab and include your input and a link to the run.

# Actor input Schema

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

Add one company per line. Accepted formats:<br>• Job-board URL: <code>https://jobs.lever.co/spotify</code>, <code>https://job-boards.greenhouse.io/discord</code><br>• Careers-page URL: <code>https://www.example.com/careers</code> (the page is scanned for an embedded job board)<br>• Explicit board token: <code>greenhouse:stripe</code>, <code>lever:spotify</code>, <code>ashby:linear</code>, <code>personio:acme</code><br>• Company name: <code>Linear</code> (likely board names are tried on each supported ATS)

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

Stop after this many jobs from each company. Set 0 for all open jobs.

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

Keep jobs whose title contains ANY of these words (case-insensitive), e.g. <code>engineer</code>, <code>sales</code>.

## `searchKeywordsInDescription` (type: `boolean`):

Match the keywords against the job description as well as the title.

## `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 where any location contains one of these texts, e.g. <code>London</code>, <code>Germany</code>, <code>Remote</code>.

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

Keep only jobs the company marks as remote, or with 'remote' in a location.

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

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

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

Only jobs posted in the last N days. Set 0 for any date. Jobs without a posting date are kept.

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

Remember the jobs you already received and output only jobs not seen in previous runs with the same 'Saved list name'. Turn this on for scheduled monitoring.

## `stateKey` (type: `string`):

Name used to remember jobs between runs in 'Only new jobs' mode. Use a different name for each company list you schedule (letters, digits and dashes), e.g. <code>fintech-targets</code>.

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

Add the plain-text job description. Emails, phone numbers and named recruiter contacts are removed.

## `includeDescriptionHtml` (type: `boolean`):

Also add the original description HTML (with contact details removed). Makes results larger.

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

Stop after this many jobs in total. Set 0 for no limit. Use it to cap the cost of a run.

## `atsToTry` (type: `array`):

Which applicant tracking systems (ATS) to query. Leave all selected unless you know which one your companies use.

## `enableSmartRecruiters` (type: `boolean`):

Also query SmartRecruiters' public Posting API. Off by default; see the README before enabling.

## Actor input object example

```json
{
  "companies": [
    "greenhouse:discord",
    "https://jobs.lever.co/spotify",
    "Linear"
  ],
  "maxJobsPerCompany": 10,
  "searchKeywordsInDescription": false,
  "remoteOnly": false,
  "postedWithinDays": 0,
  "onlyNewJobs": false,
  "stateKey": "default",
  "includeDescription": true,
  "includeDescriptionHtml": false,
  "maxItems": 0,
  "atsToTry": [
    "greenhouse",
    "lever",
    "ashby",
    "personio"
  ],
  "enableSmartRecruiters": false
}
```

# Actor output Schema

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

One record per open job.

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

For each input: detected ATS, board token, detection method and job counts.

# 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": [
        "greenhouse:discord",
        "https://jobs.lever.co/spotify",
        "Linear"
    ],
    "maxJobsPerCompany": 10
};

// Run the Actor and wait for it to finish
const run = await client.actor("leonardoo/multi-ats-company-jobs-feed").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": [
        "greenhouse:discord",
        "https://jobs.lever.co/spotify",
        "Linear",
    ],
    "maxJobsPerCompany": 10,
}

# Run the Actor and wait for it to finish
run = client.actor("leonardoo/multi-ats-company-jobs-feed").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": [
    "greenhouse:discord",
    "https://jobs.lever.co/spotify",
    "Linear"
  ],
  "maxJobsPerCompany": 10
}' |
apify call leonardoo/multi-ats-company-jobs-feed --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,leonardoo/multi-ats-company-jobs-feed"
        }
    }
}
```

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/poJOS6nCDG49gEuJC/builds/SiimzBJADlChmGXxS/openapi.json
