# ATS Jobs Feed — Greenhouse · Lever · Ashby, one schema (`multiplex/ats-jobs-feed`) Actor

Pull live job postings from company career boards on Greenhouse, Lever and Ashby through their public job-board APIs — normalised to a single schema with stable IDs, deduplication, optional PII redaction and a changes-only monitor mode.

- **URL**: https://apify.com/multiplex/ats-jobs-feed.md
- **Developed by:** [Daniel James](https://apify.com/multiplex) (community)
- **Categories:** Jobs
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

Pay per usage

This Actor is paid per platform usage. The Actor is free to use, and you only pay for the Apify platform usage, which gets cheaper the higher subscription plan you have.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-usage

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
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.
Actors are written with capital "A".

## 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.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## ATS Jobs Feed — Greenhouse · Lever · Ashby, one schema

Pull live job postings straight from company career boards — through the **official public job-board APIs** of Greenhouse, Lever and Ashby — and get them back in **one clean, normalised schema** with stable IDs, deduplication and an optional **changes-only monitor mode**.

No scraping of job aggregators, no proxies, no brittle HTML parsing: these are the JSON endpoints the ATS vendors publish precisely so third parties can consume their boards. That makes this feed fast (hundreds of jobs in seconds), reliable and compliance-friendly.

### What you get

Every job, from every board you list, in the same shape:

```json
{
  "id": "9b1f6c2a…",
  "ats": "greenhouse",
  "board": "gitlab",
  "sourceJobId": "7970199002",
  "title": "Senior Backend Engineer",
  "department": "Engineering",
  "team": "Platform",
  "location": "Remote, EMEA",
  "employmentType": "Full-time",
  "remote": true,
  "compensation": "£70K – £90K",
  "absoluteUrl": "https://boards.greenhouse.io/gitlab/jobs/7970199002",
  "publishedAt": "2026-07-01T09:12:00Z",
  "updatedAt": "2026-08-11T14:03:00Z"
}
```

- **Stable IDs** — the same job keeps the same `id` across runs, so joins and diffing downstream just work.
- **Dedupe** built in.
- **Compensation** where the ATS provides it (Ashby publishes structured pay ranges).
- **Full descriptions** optional (`includeContent`) — off by default to keep datasets lean.

### Monitor mode (`changesOnly`)

Turn any board into a change feed. The actor remembers each board's state between runs and emits only:

- `"changeType": "new"` — freshly posted jobs
- `"changeType": "updated"` — title/location/team/comp changes
- `"changeType": "removed"` — postings taken down (a strong closed-role signal)

Run it on a schedule and you have a hiring-signal pipeline: who is hiring, for what, where, and what quietly disappeared — the signal recruiters, sales teams and analysts actually want.

### Input

| Field | Example | Notes |
|---|---|---|
| `boards` | `greenhouse:gitlab`, `lever:spotify`, `ashby:Notion` | or paste board URLs. The token is the slug from the board URL. **Ashby names are case-sensitive** — `Notion`, not `notion`; an unknown Ashby board returns an empty list, and the run log warns you |
| `changesOnly` | `false` | monitor mode as above |
| `stripPii` | `true` | redacts emails/phone numbers from descriptions — keep on unless you have a lawful basis to process them |
| `includeContent` | `false` | full description HTML/text per job |
| `maxJobsPerBoard` | `0` | 0 = unlimited |

### Where do I find my board token?

- Greenhouse: `boards.greenhouse.io/TOKEN`
- Lever: `jobs.lever.co/TOKEN`
- Ashby: `jobs.ashbyhq.com/TOKEN` (exact casing)

Any company using one of these three systems for their careers page can be monitored — that's a very large share of tech and scale-up hiring.

### Honest limits

- Only boards on Greenhouse, Lever or Ashby (more ATS platforms planned — tell us which you need in the Issues tab).
- Job descriptions are customer-authored; with `stripPii` off you are responsible for any personal data they contain.
- Greenhouse/Ashby publish no rate limits; the actor is polite (retries with backoff, no hammering).

### Typical costs

The actor is pure JSON-API work — no browser — so platform usage is tiny (a three-board, 426-job run measured ~0.0015 compute units in under 6 seconds). You pay per result via the event pricing shown on this page.

# Actor input Schema

## `boards` (type: `array`):

Career boards to fetch, one per line, as `ats:token` — e.g. `greenhouse:stripe`, `lever:spotify`, `ashby:ramp`. The token is the company slug from the board URL (boards.greenhouse.io/TOKEN, jobs.lever.co/TOKEN, jobs.ashbyhq.com/TOKEN).

## `changesOnly` (type: `boolean`):

Emit only jobs that are new, changed or removed since the previous run of this actor on the same board. First run emits everything as `new`.

## `stripPii` (type: `boolean`):

Redact email addresses and phone numbers from job content, and drop recruiter/contact fields. Keep ON unless you have a lawful basis to process them (UK/EU GDPR).

## `includeContent` (type: `boolean`):

Include the full description (HTML/text) per job. Off by default to keep the dataset lean.

## `maxJobsPerBoard` (type: `integer`):

0 = unlimited.

## Actor input object example

```json
{
  "boards": [
    "greenhouse:gitlab"
  ],
  "changesOnly": false,
  "stripPii": true,
  "includeContent": false,
  "maxJobsPerBoard": 0
}
```

# Actor output Schema

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

All fetched job postings in one normalised schema (one item per job; monitor mode adds changeType new/updated/removed).

# 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 = {
    "boards": [
        "greenhouse:gitlab"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("multiplex/ats-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 = { "boards": ["greenhouse:gitlab"] }

# Run the Actor and wait for it to finish
run = client.actor("multiplex/ats-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 '{
  "boards": [
    "greenhouse:gitlab"
  ]
}' |
apify call multiplex/ats-jobs-feed --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,multiplex/ats-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/DjG2x7xCgWTc4eBvd/builds/LejainYEyCmm2a0TU/openapi.json
