# ATS Jobs by Company: Greenhouse, Lever, Ashby, Workable & More (`clearpath-data/ats-jobs-by-company`) Actor

Get every open job from any company's Greenhouse, Lever, Ashby, Workable, SmartRecruiters or Recruitee job board in one normalized dataset. Paste slugs or careers URLs; the ATS is auto-detected. Filter by keyword, location, remote, department and posting date. Salary included when published.

- **URL**: https://apify.com/clearpath-data/ats-jobs-by-company.md
- **Developed by:** [Clearpath Data](https://apify.com/clearpath-data) (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 $0.60 / 1,000 job results

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

## ATS Jobs by Company: Greenhouse, Lever, Ashby, Workable, SmartRecruiters & Recruitee job scraper

Get **every open job** from any company that hires through **Greenhouse, Lever, Ashby, Workable, SmartRecruiters or Recruitee**, in **one clean, normalized dataset**. Paste board slugs, job-board URLs or a company's careers page. The Actor detects the ATS, calls the ATS's **official public job-board API** and returns the same fields for every company, whichever ATS it uses.

- ✅ **Six ATSs, one schema.** Greenhouse, Lever (global and EU), Ashby, Workable, SmartRecruiters and Recruitee.
- ✅ **Auto-detect.** Give it `stripe`, `https://jobs.lever.co/spotify`, `https://jobs.ashbyhq.com/openai` or even `https://www.figma.com/careers/`.
- ✅ **Filters before you pay.** Title keywords, locations, remote only, departments and *posted since*. You are only charged for jobs that match.
- ✅ **Salary when published.** Greenhouse pay ranges, Lever salary ranges, Ashby compensation and Recruitee salary fields are returned as `min`, `max`, `currency` and `interval`.
- ✅ **Fast and light.** It reads official JSON APIs, with no browser and no proxy. Most runs finish in seconds.
- ✅ **Bad inputs don't break the run.** An unknown slug is logged as a warning and listed in the run report, and the run carries on.
- ✅ **Optional hiring summary per company:** new jobs in the last 7 and 30 days, top departments and locations, and remote share.

### What can I use it for?

| Who | Use case |
|---|---|
| Sales & RevOps | **Hiring-intent signals.** "Company X opened 12 sales roles this month" is a reason to reach out. Run it on a schedule over your target-account list. |
| Recruiters & agencies | Track every open role at client and prospect companies, and spot new roles the day they're posted. |
| Job boards & newsletters | Backfill a niche job board (for example, remote engineering at AI startups) with fresh, structured postings. |
| Analysts & investors | Watch headcount growth, department mix, remote share and pay bands across a portfolio of companies. |

### How to use it

1. Open the **Input** tab and add companies to **Companies**, one per line. Any of these forms works:
   - a plain slug: `stripe` (the ATS is auto-detected)
   - a prefixed slug: `lever:palantir`, `ashby:ramp`, `greenhouse:databricks`, `workable:huggingface`, `smartrecruiters:BoschGroup` or `recruitee:bunq`
   - a job-board URL: `https://job-boards.greenhouse.io/anthropic`, `https://jobs.lever.co/spotify`, `https://jobs.ashbyhq.com/openai`, `https://apply.workable.com/huggingface/`, `https://careers.smartrecruiters.com/BoschGroup` or `https://bunq.recruitee.com`
   - a company careers page: `https://www.figma.com/careers/`, `https://huggingface.co/careers` or `https://jobs.bosch.com` (the Actor looks for an embedded board)
2. Optionally add filters, a total or per-company job limit, and choose how descriptions are included.
3. Click **Start**. Download the results as JSON, CSV, Excel or XML, or fetch them with the Apify API.

**Tip: finding a company's slug.** It is the part of the board URL after the domain, or the subdomain for Recruitee. For example, `job-boards.greenhouse.io/`**`airbnb`**, `jobs.lever.co/`**`spotify`**, `jobs.ashbyhq.com/`**`ramp`**, `apply.workable.com/`**`huggingface`**, `careers.smartrecruiters.com/`**`BoschGroup`** and **`bunq`**`.recruitee.com`. SmartRecruiters IDs are case-sensitive.

#### Input example

```json
{
    "companies": ["stripe", "https://jobs.lever.co/spotify", "https://jobs.ashbyhq.com/openai"],
    "keywords": ["engineer"],
    "locations": ["London", "Remote"],
    "remoteOnly": false,
    "departments": [],
    "postedSince": "30 days",
    "maxResults": 1000,
    "maxResultsPerCompany": 0,
    "descriptionMode": "text",
    "includeCompanySummary": true
}
```

| Field | What it does |
|---|---|
| `companies` | **Required.** Slugs or URLs, as described above. |
| `ats` | Which ATS to use for *plain* slugs: `auto` (the default) tries Greenhouse, Ashby, Lever, Workable, Recruitee and then SmartRecruiters. |
| `keywords` | Keeps jobs whose **title** contains any of the words. Turn on `searchInDescription` to also search descriptions. |
| `locations` | Keeps jobs whose location, secondary locations or country contains any of the strings. |
| `remoteOnly` | Keeps only fully remote jobs. |
| `departments` | Keeps jobs whose department or team contains any of the strings. |
| `postedSince` | Accepts `2026-09-01` or a relative value such as `7 days`, `2 weeks` or `1 month`. |
| `maxResults` / `maxResultsPerCompany` | Caps on saved jobs (newest first). `0` means no limit. These also cap your cost. |
| `descriptionMode` | `none`, `text` (the default), `html` or `both`. For SmartRecruiters, descriptions need one extra request per saved job, so `none` is much faster on big SmartRecruiters boards. |
| `includeCompanySummary` | Adds one hiring summary per company, saved to the `COMPANY_SUMMARIES` record. |

### Output

Each job is one row, and every ATS produces the same fields:

```json
{
  "id": "ashby:openai:539aa9e9-76e0-4408-b47b-3bd569a81f91",
  "company": "OpenAI",
  "companySlug": "openai",
  "ats": "ashby",
  "jobId": "539aa9e9-76e0-4408-b47b-3bd569a81f91",
  "title": "Technical Accounting Lead, Ads Revenue",
  "department": "Finance",
  "team": "Finance",
  "location": "San Francisco",
  "locations": ["San Francisco", "New York City"],
  "country": "United States",
  "isRemote": false,
  "workplaceType": "hybrid",
  "employmentType": "FullTime",
  "postedAt": "2026-10-08T23:38:34.938Z",
  "updatedAt": null,
  "jobUrl": "https://jobs.ashbyhq.com/openai/539aa9e9-76e0-4408-b47b-3bd569a81f91",
  "applyUrl": "https://jobs.ashbyhq.com/openai/539aa9e9-76e0-4408-b47b-3bd569a81f91/application",
  "salary": { "min": 216000, "max": 240000, "currency": "USD", "interval": "year", "text": "$216K - $240K" },
  "scrapedAt": "2026-10-09T05:26:28.242Z",
  "descriptionText": "About the Team\n\nOpenAI Finance ensures the organization is positioned for long-term success as we pursue our mission. …"
}
```

| Field | Notes |
|---|---|
| `id` | Stable key `ats:companySlug:jobId`. Use it to de-duplicate or compare runs. |
| `company` | Company name from the board, or the slug if the board doesn't publish a name. |
| `department`, `team` | As published. Greenhouse, Workable and Recruitee have departments but no teams. On SmartRecruiters, `team` is the job function. |
| `location`, `locations`, `country` | Primary location, all locations, and country when the ATS provides it (all except Greenhouse). Lever and SmartRecruiters give a country code, the others a country name. |
| `isRemote`, `workplaceType` | `isRemote` is `true` only for fully remote jobs. It is `false` for hybrid or on-site jobs, and `null` when the posting doesn't say. |
| `employmentType` | Exactly as the ATS publishes it, for example `FullTime` (Ashby), `Permanent` (Lever), `Full-time` (Workable, SmartRecruiters) or `fulltime_permanent` (Recruitee). It is often `null` on Greenhouse. |
| `postedAt`, `updatedAt` | ISO 8601 dates. `updatedAt` is only available on Greenhouse and Recruitee. Workable gives a date without a time. |
| `salary` | `null` unless the employer publishes pay on the board. |
| `descriptionText`, `descriptionHtml` | Depend on `descriptionMode`. |

The dataset has three views: **Overview**, **Salaries** and **All fields**.

**Run report.** The `RUN_REPORT` record in the run's key-value store lists every input with its status (`ok`, `not_found`, `error` or `skipped`), the detected ATS and the job counts. Use it to see which slugs didn't resolve.

**Company summary** (optional). Each summary has `openJobs`, `matchingJobs`, `newJobsLast7Days`, `newJobsLast30Days`, `remoteJobs`, `jobsWithSalary`, `newestPostedAt`, `topDepartments` and `topLocations`.

### Pricing

This Actor is **pay per event**. You pay only for the results you get, and Apify platform usage is included in the price.

| Event | Free & Bronze plans | Silver plan | Gold plan and above | When it's charged |
|---|---|---|---|---|
| Actor start | Apify's default start fee | same | same | Once per run (per GB of memory) |
| **Job** (primary) | **$0.001** per job ($1.00 per 1,000) | $0.0008 per job | $0.0006 per job | For each job saved to the dataset, after filters |
| Company summary | $0.005 per company | $0.005 | $0.005 | Only when `includeCompanySummary` is on |

Examples (Free/Bronze prices):

- 1,000 jobs cost **$1.00**.
- A daily check of 50 companies with `postedSince: "1 day"` usually returns only a handful of new jobs, so it costs cents per day.
- Inputs that fail (an unknown slug, for example) add **no job or summary charges**.

To control your spending, use `maxResults` or set a **maximum cost per run** in the run options. The Actor stops cleanly when that limit is reached.

### FAQ and limits

**Is this legal?** The Actor reads only the **public job-posting APIs** that Greenhouse, Lever, Ashby, Workable, SmartRecruiters and Recruitee provide so that companies can show their jobs on their own websites. It needs no login and reads no private data. You are responsible for how you use the data. Check the ATS vendors' and employers' terms and any data-protection rules that apply to your use case.

**Which ATSs are supported?** Greenhouse (`boards.greenhouse.io` and `job-boards.greenhouse.io`), Lever (`jobs.lever.co` and EU `jobs.eu.lever.co`), Ashby (`jobs.ashbyhq.com`), Workable (`apply.workable.com/<company>`), SmartRecruiters (`careers.smartrecruiters.com/<CompanyId>` and `jobs.smartrecruiters.com`) and Recruitee (`<company>.recruitee.com`). Workday and other ATSs are not supported yet. If you need one, open an issue.

**Can it find *all* companies on these ATSs?** No. The ATSs publish no directory of boards, so you provide the company list.

**Why is my company "not_found"?** The slug doesn't match a public board, the company uses a different ATS, or its board is private. SmartRecruiters returns an empty list for unknown IDs, so an empty SmartRecruiters board is also reported as `not_found`; check the ID's capitalization. Open the company's careers page, click a job, and copy the board URL into the input.

**Why is `salary` empty?** Most employers don't publish pay on their board. Salary is filled in only when the ATS returns it.

**Why are `employmentType` and `isRemote` sometimes `null`?** Greenhouse's public API doesn't have structured fields for them. Where possible, the Actor infers remote status from the location text, for example "Remote (US)".

**How fresh is the data?** It is fetched live from the ATS during your run. There is no cache.

**How big can a run be?** Large boards (800+ jobs) load in a few seconds each. In our tests, 15 companies and 4,300 jobs, with full descriptions, finished in about 10 seconds. SmartRecruiters is the exception for descriptions: they need one request per job. In our tests, Bosch Group's 4,878 jobs took about 10 seconds without descriptions and several minutes with them. For lists of hundreds of companies, increase `maxConcurrency` or split the list.

**Can I get only new jobs every day?** Yes. Schedule the Actor with `postedSince: "1 day"`, or compare `id` values between runs.

**Found a bug or need a field?** Open an issue on the **Issues** tab. We reply within a few days.

# Changelog

This Actor's version history is a separate document: https://apify.com/clearpath-data/ats-jobs-by-company/changelog.md

# Actor input Schema

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

One company per line. Accepts a board slug ("stripe"), a prefixed slug ("lever:spotify", "workable:huggingface", "smartrecruiters:BoschGroup", "recruitee:bunq"), a job-board URL (job-boards.greenhouse.io/airbnb, jobs.lever.co/palantir, jobs.ashbyhq.com/openai, apply.workable.com/huggingface, careers.smartrecruiters.com/BoschGroup, bunq.recruitee.com), or a company careers page URL (the Actor looks for an embedded Greenhouse, Lever, Ashby, Workable, SmartRecruiters or Recruitee board). SmartRecruiters company IDs are case-sensitive.

## `ats` (type: `string`):

Which ATS to query for plain slugs such as "stripe". "Auto-detect" tries Greenhouse, Ashby, Lever, Workable, Recruitee, then SmartRecruiters, and uses the first board with open jobs. URLs and prefixed slugs always use their own ATS.

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

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

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

When on, keywords are also matched against the job description text.

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

Keep only jobs whose location (or any secondary location / country) contains at least one of these strings, e.g. "London", "Germany", "Remote".

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

Keep only jobs marked remote by the ATS, or whose location says Remote/Anywhere.

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

Keep only jobs whose department or team contains at least one of these strings, e.g. "Engineering", "Sales".

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

Keep only jobs first published on or after this date. Use an absolute date (2026-09-01) or a relative one ("7 days", "2 weeks", "1 month"). Jobs without a published date are excluded when this is set.

## `maxResults` (type: `integer`):

Stop after saving this many jobs across all companies. 0 = no limit. You pay per saved job, so this also caps the cost.

## `maxResultsPerCompany` (type: `integer`):

Save at most this many jobs per company (newest first). 0 = no limit.

## `descriptionMode` (type: `string`):

Include the job description as plain text, HTML, both, or not at all (smallest output, fastest). SmartRecruiters needs one extra request per saved job for descriptions.

## `includeCompanySummary` (type: `boolean`):

Also build one hiring summary per company (open jobs, new jobs in the last 7/30 days, top departments and locations, remote share). Saved to the key-value store record COMPANY_SUMMARIES. Charged per company (see Pricing).

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

How many companies to fetch at the same time.

## Actor input object example

```json
{
  "companies": [
    "stripe",
    "https://jobs.lever.co/spotify",
    "https://jobs.ashbyhq.com/openai",
    "https://bunq.recruitee.com"
  ],
  "ats": "auto",
  "keywords": [],
  "searchInDescription": false,
  "locations": [],
  "remoteOnly": false,
  "departments": [],
  "maxResults": 300,
  "maxResultsPerCompany": 100,
  "descriptionMode": "text",
  "includeCompanySummary": false,
  "maxConcurrency": 5
}
```

# Actor output Schema

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

Normalized job postings

## `runReport` (type: `string`):

Per-company status and counts

## `companySummaries` (type: `string`):

Only present when includeCompanySummary is on

# 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",
        "https://jobs.lever.co/spotify",
        "https://jobs.ashbyhq.com/openai",
        "https://bunq.recruitee.com"
    ],
    "maxResults": 300,
    "maxResultsPerCompany": 100
};

// Run the Actor and wait for it to finish
const run = await client.actor("clearpath-data/ats-jobs-by-company").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",
        "https://jobs.lever.co/spotify",
        "https://jobs.ashbyhq.com/openai",
        "https://bunq.recruitee.com",
    ],
    "maxResults": 300,
    "maxResultsPerCompany": 100,
}

# Run the Actor and wait for it to finish
run = client.actor("clearpath-data/ats-jobs-by-company").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",
    "https://jobs.lever.co/spotify",
    "https://jobs.ashbyhq.com/openai",
    "https://bunq.recruitee.com"
  ],
  "maxResults": 300,
  "maxResultsPerCompany": 100
}' |
apify call clearpath-data/ats-jobs-by-company --silent --output-dataset

```

## MCP server setup

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

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/1ghitDj85pq2hs9Hf/builds/p7M696G8BCoBTWwX9/openapi.json
