# Greenhouse Jobs Scraper & API (+ Lever, Ashby, Workable) (`wintersworks/ats-job-board-feeds`) Actor

Greenhouse jobs from any company's Greenhouse job board, plus Lever, Ashby, Workable and SmartRecruiters. Output: normalized job listings with location, remote flag, department, salary and apply link. $1.50 per 1,000 jobs. Keyword, location and remote filters, new-job monitoring.

- **URL**: https://apify.com/wintersworks/ats-job-board-feeds.md
- **Developed by:** [Winters Works](https://apify.com/wintersworks) (community)
- **Categories:** Jobs, Automation, Developer tools
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$1.50 / 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.

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 Jobs Scraper & API (+ Lever, Ashby, Workable, SmartRecruiters)

**Greenhouse jobs, pay per result: $1.50 per 1,000 jobs.** Try it on the Apify Free plan: the $5 monthly credit covers about 3,000 jobs.

Pull live Greenhouse jobs from any company's careers page into one clean, flat dataset, plus Lever, Ashby, Workable and SmartRecruiters. Give it company names or careers-page URLs and it returns normalized jobs from **Greenhouse, Lever, Ashby, Workable and SmartRecruiters**, with keyword, location, remote, department and date filters, salary data where the company publishes it, and a **new-jobs-only monitoring mode** for scheduled runs.

**Keywords:** Greenhouse jobs API, Lever jobs API, Ashby job scraper, Workable jobs, SmartRecruiters jobs, company careers page scraper, job listings API, new job alerts, hiring signals.

It uses only the **official public job-board APIs** that these applicant tracking systems (ATS) publish for embedding careers pages. No login, no proxies, no HTML scraping, no browser. That makes it fast, stable and very cheap.

### What you can do with it

- **Job aggregators and job boards:** build a feed of direct-from-employer listings with consistent fields across five ATS platforms.
- **Recruiters and sourcers:** watch target companies for new roles in a department or location.
- **Sales and market intelligence:** hiring is a buying signal. Track which companies are hiring for security, data, DevRel or RevOps roles and reach out while the budget is fresh.
- **Job seekers:** monitor the companies you care about and get only the new postings each day.
- **Researchers and analysts:** measure hiring trends, pay transparency, remote share and headcount growth by company.

### Supported ATS

| ATS | Careers URL looks like | Notes |
|---|---|---|
| Greenhouse | `boards.greenhouse.io/stripe`, `job-boards.greenhouse.io/stripe` | Pay ranges when published |
| Lever | `jobs.lever.co/spotify` (also EU) | Salary range and workplace type when published |
| Ashby | `jobs.ashbyhq.com/ramp` | Compensation summary and salary range |
| Workable | `apply.workable.com/huggingface` | Public widget API |
| SmartRecruiters | `jobs.smartrecruiters.com/BoschGroup` | Public postings API |

Pass a **URL** and the ATS is detected automatically. Pass a **bare slug** (like `stripe`) and the Actor tries every supported ATS and returns whichever has jobs. To force one, write `lever:spotify`.

### Input

| Field | Description |
|---|---|
| `companies` | Careers URLs or slugs. Default: `stripe`, `spotify`, `ramp` |
| `keyword` | Words that must all appear in title, department, team or description |
| `location` | Text the location must contain, e.g. `London` |
| `remoteOnly` | Only remote jobs |
| `department` | Text the department or team must contain |
| `postedWithinDays` | Only jobs first posted in the last N days |
| `includeDescription` | Add `descriptionText` (HTML converted to plain text) |
| `maxResults` / `maxPerCompany` | Caps (newest first). 0 = unlimited |
| `onlyNew` | Return only jobs not seen in earlier runs |
| `stateStoreName` | Named key-value store holding seen job IDs |

Example, remote data jobs posted this week:

```json
{
  "companies": ["https://boards.greenhouse.io/stripe", "ramp", "lever:spotify"],
  "keyword": "data engineer",
  "remoteOnly": true,
  "postedWithinDays": 7,
  "maxPerCompany": 0,
  "maxResults": 0
}
```

### Output

One flat record per job:

```json
{
  "ats": "ashby",
  "company": "ramp",
  "jobId": "34413f8d-26bf-4bbc-8ade-eb309a0e2245",
  "title": "Security Engineer, Cloud",
  "department": "Engineering",
  "team": "Backend",
  "location": "New York, NY (HQ); Remote (Canada); Remote (US)",
  "remote": true,
  "employmentType": "FullTime",
  "compensation": "$211.4K - $290.6K",
  "compensationMin": 211400,
  "compensationMax": 290600,
  "compensationCurrency": "USD",
  "compensationInterval": "year",
  "postedAt": "2026-04-07T17:12:35.753Z",
  "updatedAt": null,
  "applyUrl": "https://jobs.ashbyhq.com/ramp/34413f8d-.../application",
  "scrapedAt": "2026-10-10T12:00:00.000Z"
}
```

Export as JSON, CSV, Excel or HTML, or read it through the Apify API. Not every ATS provides every field; missing values are `null`. `updatedAt` is available on Greenhouse only. The `remote` flag uses the ATS's own flag where available, otherwise the location and title text.

### Scheduling and monitoring for new jobs

1. Set `onlyNew: true` and a `stateStoreName` such as `my-fintech-watchlist`.
2. Create a Schedule in Apify (daily or hourly).
3. Connect a webhook, Zapier, Make or n8n integration to the run's dataset.

The first run returns all matching jobs and records their IDs. Later runs return only postings that are new, so you pay only for new jobs. Use a different `stateStoreName` for each separate watchlist.

### Pricing

| Event | Price | Per 1,000 |
|---|---|---|
| `job-result` (one job returned) | $0.0015 | $1.50 |

Examples: 1,000 jobs = $1.50, 10,000 jobs = $15, 100,000 jobs = $150.

You're never charged for failed or empty lookups, and the run's status message tells you why any input came back short (capped by `maxPerCompany`/`maxResults`, board not found, or a board with 0 open jobs).

Filters are applied first, and in `onlyNew` mode only new jobs count. The Apify Free plan's monthly credit covers thousands of jobs. Set a maximum cost per run and the Actor stops cleanly when it is reached.

### Integrations and AI agents (MCP)

#### Scheduling and webhooks

Run the Actor on an Apify Schedule, for example once a day with your list of target companies, and add a webhook or an email notification for when the run finishes. Set `postedWithinDays` (say `1` or `7`) to pull only recent postings, or use `onlyNew` with a `stateStoreName` to get just the jobs you haven't seen before.

#### Apify platform integrations

These are features of the Apify platform and work with any Actor, this one included: Make, n8n, Zapier, Google Sheets export, Slack notifications, the Apify API, and the official JavaScript and Python clients. Anything that can call the Apify API or receive a webhook (Clay, Airtable, your own backend) can start a run and read the dataset.

#### MCP for AI agents

Apify's hosted MCP server can expose this Actor as a tool your AI assistant calls directly:

`https://mcp.apify.com?actors=wintersworks/ats-job-board-feeds`

Example config for Claude Desktop, Cursor or Claude Code (an MCP server entry that takes a URL and headers):

```json
{
  "mcpServers": {
    "ats-job-board-feeds": {
      "url": "https://mcp.apify.com?actors=wintersworks/ats-job-board-feeds",
      "headers": {
        "Authorization": "Bearer YOUR_APIFY_TOKEN"
      }
    }
  }
}
```

Then ask things like:

- "List remote engineering roles posted in the last 7 days at stripe and figma (Greenhouse)."
- "Which of ramp, spotify and huggingface posted data jobs this week, and which show a salary range?"
- "Check lever:spotify and the Ashby board for ramp for new security roles in London, and give me the apply links."

#### Code examples

Python:

```python
from apify_client import ApifyClient

client = ApifyClient("YOUR_APIFY_TOKEN")
run = client.actor("wintersworks/ats-job-board-feeds").call(run_input={
    "companies": ["stripe", "ramp", "lever:spotify"],
    "keyword": "data engineer",
    "remoteOnly": True,
    "postedWithinDays": 7,
    "maxResults": 100,
})
for job in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(job["company"], job["title"], job["applyUrl"])
```

JavaScript:

```javascript
import { ApifyClient } from 'apify-client';

const client = new ApifyClient({ token: 'YOUR_APIFY_TOKEN' });
const run = await client.actor('wintersworks/ats-job-board-feeds').call({
    companies: ['stripe', 'ramp', 'lever:spotify'],
    department: 'Engineering',
    onlyNew: true,
    stateStoreName: 'my-watchlist',
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items.length, 'new jobs');
```

### FAQ

**Is this legal and allowed?** It reads only the public job-board endpoints that Greenhouse, Lever, Ashby, Workable and SmartRecruiters offer for embedding careers pages. It does not log in or bypass anything. Job postings are published by the employers. You are responsible for how you use the data, including applicable privacy and marketing laws.

**How do I find a company's slug?** Open its careers page and look at the apply URL, e.g. `jobs.lever.co/spotify` means slug `spotify`. Or paste the careers URL directly.

**A company returned nothing.** It may use a different ATS (Workday, iCIMS and others are not supported), its slug may differ from its name, or it may have no open roles. Many companies embed a Greenhouse or Ashby board inside their own domain; use the underlying board URL or `ats:slug`.

**Can I get all jobs from an ATS?** No. There is no public index of every company; you supply the companies.

**Does it work for large employers?** Yes. Pagination is handled for SmartRecruiters; tens of thousands of jobs can be fetched with `maxResults: 0`. Descriptions on SmartRecruiters need one extra request per job, so they are slower.

**Are salaries included?** When the employer publishes them (common in the US due to pay-transparency laws), they appear in the `compensation*` fields.

Built by Winters Works. Questions or a missing ATS? open an issue on the Actor page.

### Is it legal? (public data only)

Yes, in the sense that it only reads public or official data: the public job-board endpoints of Greenhouse, Lever, Ashby, Workable and SmartRecruiters. It does not log in, bypass paywalls or access private data. You remain responsible for how you use the results, including privacy, copyright and marketing laws. Not affiliated with or endorsed by the data sources.

### Quick start and cost

Run it with the prefilled input to see sample output in seconds; the default run costs only a few cents at most. Then adjust the input and schedule it.

### Use from code and AI agents

Call it from any language with the Apify API, or let an AI agent find and run it through the [Apify MCP server](https://mcp.apify.com).

```python
from apify_client import ApifyClient
run = ApifyClient("<YOUR_APIFY_TOKEN>").actor("wintersworks/ats-job-board-feeds").call(run_input={"companies": ["stripe", "spotify"], "keyword": "engineer"})
items = ApifyClient("<YOUR_APIFY_TOKEN>").dataset(run["defaultDatasetId"]).list_items().items
```

Results land in the run's dataset (JSON, CSV, Excel). Set a maximum charge per run in the run options to cap spend.

### About

Built and maintained by Winters Works. Questions or feature requests: open an issue on the Actor page or email wintersworks.shop@gmail.com.

### More from Winters Works

- [Bulk Email Verifier & MX Record Checker](https://apify.com/wintersworks/bulk-email-verifier-dns): clean an email list before you send. Syntax, MX lookup, disposable and role-address checks, no SMTP probing.
- [iOS App Store Reviews Scraper](https://apify.com/wintersworks/appstore-reviews-scraper): pull App Store reviews and ratings for any app, with date, rating and keyword filters.
- [Website Tech Stack & SEO Audit](https://apify.com/wintersworks/website-tech-stack-seo-audit): see what a list of sites runs on, plus SEO basics, security headers, SSL expiry and a 0-100 score.
- [ClinicalTrials.gov Scraper & Monitor](https://apify.com/wintersworks/clinical-trials-search-monitor): search trials by condition, drug, sponsor or location, and track what's new or updated between runs.

# Actor input Schema

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

Careers-page URLs (boards.greenhouse.io/stripe, jobs.lever.co/spotify, jobs.ashbyhq.com/ramp, apply.workable.com/huggingface, jobs.smartrecruiters.com/BoschGroup) or bare company slugs. A bare slug is tried on every supported ATS. Prefix with an ATS to force it, e.g. lever:spotify.

## `keyword` (type: `string`):

Only jobs whose title, department, team or description contain ALL of these words (case-insensitive). Example: data engineer

## `location` (type: `string`):

Only jobs whose location contains this text (case-insensitive). Example: London, Germany, New York

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

Only return jobs flagged or described as remote.

## `department` (type: `string`):

Only jobs whose department or team contains this text. Example: Engineering

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

Only jobs first posted in the last N days. 0 = no limit.

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

Add the job description converted from HTML to plain text. (SmartRecruiters needs one extra request per job.)

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

Stop after this many jobs across all companies. 0 = unlimited.

## `maxPerCompany` (type: `integer`):

Cap per company (newest first). 0 = unlimited.

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

Return only jobs not seen in previous runs. Seen job IDs are kept in a named key-value store, so scheduled runs yield just new postings. The first run returns everything.

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

Named key-value store used by 'Only new jobs'. Use different names for different monitors.

## Actor input object example

```json
{
  "companies": [
    "stripe",
    "spotify",
    "ramp"
  ],
  "remoteOnly": false,
  "postedWithinDays": 0,
  "includeDescription": false,
  "maxResults": 6,
  "maxPerCompany": 2,
  "onlyNew": false,
  "stateStoreName": "ats-job-feeds-seen"
}
```

# Actor output Schema

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

All result items from the run's default dataset.

# 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",
        "spotify",
        "ramp"
    ],
    "maxResults": 6,
    "maxPerCompany": 2
};

// Run the Actor and wait for it to finish
const run = await client.actor("wintersworks/ats-job-board-feeds").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",
        "spotify",
        "ramp",
    ],
    "maxResults": 6,
    "maxPerCompany": 2,
}

# Run the Actor and wait for it to finish
run = client.actor("wintersworks/ats-job-board-feeds").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",
    "spotify",
    "ramp"
  ],
  "maxResults": 6,
  "maxPerCompany": 2
}' |
apify call wintersworks/ats-job-board-feeds --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,wintersworks/ats-job-board-feeds"
        }
    }
}
```

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/G7UucYp65JLIZn1z4/builds/epyXv3KRfXcrhgIl0/openapi.json
