# Career Site Jobs API: Workday, Greenhouse, Lever, Ashby (`fetchgrove/ats-career-jobs`) Actor

Every open job from company career sites in one format: Workday, Greenhouse, Lever, Ashby, Workable, Recruitee and Personio. Give a website and it finds the job board. Pay ranges where published, a hiring summary per company, and on repeat runs only new, changed and closed jobs.

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

## Pricing

from $0.70 / 1,000 jobs

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

## Career Site Jobs API: Workday, Greenhouse, Lever, Ashby

Give it a list of companies and get every open role from their official career sites, cleaned into one format. Add a company's website and it finds the job board for you. Run it on a schedule and it tells you which roles are new, changed or gone.

### Supported job boards

Workday, Greenhouse, Lever, Ashby, Workable, Recruitee, Personio, BambooHR and Teamtailor. Boards are read from their public job listings, the same ones shown on each company's careers page. Workday sites are read slowly, one request a second, and only where the site allows automated visits. BambooHR and Teamtailor sites that ask AI tools not to use their content are skipped, free of charge.

### What you get

**One row per job:** title, department, team, locations, remote flag, employment type, pay range (when the company publishes it), job link, apply link, posted date, and optionally the full description as plain text.

**One summary row per company:** which job board it uses, how many roles are open, counts by department and location, and how many roles are new or removed since the last run. It also carries hiring signals: roles opened and closed in the last 7 and 30 days, median days a role stays open, net change by department, and a growing, stable or shrinking trend once a company has been tracked for a week.

No recruiter names, emails or phone numbers are included.

### Use it for

- **Sales signals**: a company hiring five salespeople in Dublin is a company that is growing there.
- **Recruiting and market research**: track roles, locations and pay ranges across competitors.
- **Job boards and newsletters**: pull fresh roles from many companies into one feed.
- **AI agents**: "is this company hiring engineers?" answered from the source.

### How to use it

Add companies, one per line, in any of these forms:

| Form | Example |
|---|---|
| Company website | `https://www.notion.com` |
| Job board link | `https://boards.greenhouse.io/airbnb`, `https://jobs.lever.co/spotify`, `https://jobs.ashbyhq.com/ramp` |
| Board name | `greenhouse:airbnb`, `lever:spotify`, `ashby:ramp`, `workable:name`, `recruitee:name`, `personio:name`, `bamboohr:name`, `teamtailor:name` |
| Workday career site | `https://nvidia.wd5.myworkdayjobs.com/NVIDIAExternalCareerSite` |
| Board name (Workday) | `workday:nvidia.wd5/NVIDIAExternalCareerSite` |

Turn on **Only changes** to get just new, changed and removed roles on repeat runs. Leave the input empty and it checks one example company.

### Filters (free)

Narrow the jobs before you pay for them:

- **Title words**: `engineer` matches "Senior Engineer" and "Engineers"; `engineer*` also matches "Engineering".
- **Words to leave out**: for example `intern`, `contract`.
- **Locations**: a country name or code matches every city in it ("United States", "UK", "DE"); anything else matches part of the location text.
- **Remote only**, **posted after** a date or within a period ("7 days"), and **departments**.

You pay only for jobs that pass the filters.

### Output example

Real output (shortened):

```json
{
  "itemType": "company-summary",
  "company": "https://www.notion.com",
  "ats": "ashby",
  "boardSlug": "notion",
  "openJobs": 128,
  "departments": { "Sales": 44, "People": 16, "Engineering": 14 },
  "locations": { "San Francisco, California": 66, "New York, New York": 46, "Dublin, Ireland": 17 }
}
```

```json
{
  "itemType": "job",
  "ats": "ashby",
  "title": "Software Engineer, AI Connections (Developer Platform)",
  "department": "Engineering",
  "locations": ["San Francisco, California", "New York, New York"],
  "remote": true,
  "employmentType": "full-time",
  "url": "https://jobs.ashbyhq.com/notion/1fc309c8-da20-4ff2-84c7-8b863ece2b0a",
  "postedAt": "2026-08-24T14:44:49.699Z",
  "changeType": null
}
```

### Pricing

You pay for results, not for failures. A company whose board cannot be found or read costs nothing.

| What | Price |
|---|---|
| Company checked | $0.01 per company |
| Company checked with Only changes (repeat monitoring) | $0.002 per company, instead of $0.01 |
| Job | $0.001 per job ($1 per 1,000) |
| New or changed job (repeat runs) | $0.002 per job, on top of the job price |
| Finding the board from a website | $0.005 per company, only when you give a website instead of a board link |
| Run start | $0.00005 per run (5 cents per 1,000 runs) |

Example: 20 companies with 50 open roles each costs about $0.20 + $1.00 = $1.20.

Example: a daily Only changes run over the same 20 companies costs $0.04 plus only the jobs that are new or changed.

Free Apify plan: up to 10 companies and 200 jobs per company per run.

### Good to know

- **Pay ranges** appear only when the company publishes them on its board.
- **Change tracking** is stored in your own Apify account, so each account sees its own history. The first run sets the baseline.
- **Polite by design**: at most two requests a second to any site (one a second for Workday), and sites that ask automated tools not to visit them are skipped and marked as not available.

### Support

Open an issue on this page. We reply within two business days.

This tool is not affiliated with any of the job-board providers named above.

# Actor input Schema

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

One per line: a company website or domain (e.g. https://www.notion.com), a job-board URL (e.g. https://boards.greenhouse.io/airbnb, https://jobs.lever.co/spotify, https://jobs.ashbyhq.com/ramp, https://nvidia.wd5.myworkdayjobs.com/NVIDIAExternalCareerSite, https://nycballet.bamboohr.com/careers, https://career.teamtailor.com/jobs), or ats:slug where ats is greenhouse, lever, ashby, workable, recruitee, personio, bamboohr or teamtailor (e.g. greenhouse:airbnb, bamboohr:nycballet, teamtailor:career; a Teamtailor career site on its own domain is teamtailor:{host}, e.g. teamtailor:jobs.tibber.com). Workday career sites: give the career-site URL (with or without a locale such as /en-US/) or workday:{tenant}.wd{N}/{site}, e.g. workday:nvidia.wd5/NVIDIAExternalCareerSite; a website that links to its Workday site is found too, but Workday sites are never guessed. Workday sites are read politely: robots.txt first (a site whose robots.txt disallows its career-site path or job-list path is skipped), at most one request per second per Workday host, no login or cookies, and a site that blocks the request (HTTP 403, a bot check, repeated 429) is reported as a free error item and not retried. Workday lists at most 2,000 jobs per site; Workday site ids are not case-sensitive (the site's own spelling is used in the output). A company website that links to its BambooHR or Teamtailor board is found too, including a Teamtailor career site on the company's own domain; BambooHR boards are never guessed. BambooHR and Teamtailor sites whose robots.txt (for the whole site or for its job pages) or response says Content-Signal ai-input=no or search=no (they ask automated AI tools not to use their content) are skipped as a free error item. A board named more than once, in any form (greenhouse:airbnb and https://boards.greenhouse.io/airbnb, a website and its board link, or a Teamtailor tenant and its career site's own domain such as teamtailor:tibber and https://tibber.com), is read and charged once. If empty, the run checks one example company (greenhouse:airbnb).

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

Add each job's description as plain text (HTML removed, at most 20,000 characters). Email addresses and phone numbers are removed. Workday sites need one extra request per returned job at one request per second (about 17 minutes for 1,000 jobs), so set Max jobs per company or filters to keep runs short; with descriptions on, Workday jobs also list every location and the exact posted date. BambooHR also needs one extra request per returned job (at most two a second per site), which adds each job's posted date and published pay.

## `onlyChanges` (type: `boolean`):

Incremental mode: return only jobs that are new on the board since your previous run with the same settings, jobs whose title, locations, department, pay, employment type or remote status changed, plus free markers for returned jobs that left the board. A job posted before your previous run is never reported as new. The first run with given filters returns every matching job as the baseline. Each filter set and each saved task keeps its own state, and full runs (this option off) keep theirs, so an occasional full export never hides a new job from your alerts. Jobs beyond Max jobs per company (or the free-plan cap) are simply not returned, and later runs do not return them either: raise the limit to get them all. State is kept in a key-value store named ats-jobs-state in your own account.

## `changedJobsOnly` (type: `boolean`):

Same as onlyChanges; either one switches incremental mode on. Meant for alerts without webhooks: schedule the actor (for example daily) with changedJobsOnly true, and each run's dataset holds only the company summaries plus jobs that are new on the board, changed or removed since the previous run with the same settings, so a run whose job items list is empty means nothing changed. Combine with filters to watch only the roles you care about; only jobs that pass the filters are returned or charged, and each filter set (and each saved task) keeps its own state, so its first run is a baseline. New or changed jobs beyond Max jobs per company are not returned later; raise the limit if you need every one.

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

Maximum job items returned per company (1–5,000). Filters apply first, so the limit counts matching jobs (a job whose posted date is only on its own page counts once that date passes). In incremental mode, new or changed jobs beyond the limit are not returned by later runs either.

## `filters` (type: `object`):

Free filters, applied before any job is returned or charged. Fields combine with AND; inside a list, any item may match. The company summary still counts every open job (openJobs) and adds matchingJobs. Example: {"titleKeywords": \["engineer\*"], "locations": \["United Kingdom"], "postedAfter": "30 days"}.

## Actor input object example

```json
{
  "companies": [
    "https://www.notion.com",
    "greenhouse:airbnb"
  ],
  "includeDescription": false,
  "onlyChanges": false,
  "maxJobsPerCompany": 1000
}
```

# Actor output Schema

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

One row per open job plus one summary row per company.

# 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://www.notion.com",
        "greenhouse:airbnb"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("fetchgrove/ats-career-jobs").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://www.notion.com",
        "greenhouse:airbnb",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("fetchgrove/ats-career-jobs").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://www.notion.com",
    "greenhouse:airbnb"
  ]
}' |
apify call fetchgrove/ats-career-jobs --silent --output-dataset

```

## MCP server setup

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

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/I2CRblfA2H5FUE3g1/builds/kj0wzx1dyGuaaq7Fy/openapi.json
