# Career Site Jobs Feed (Greenhouse, Lever, Ashby, Workday) (`tillwork/ats-jobs-feed`) Actor

Pull every open job from company career sites on Greenhouse, Lever, Ashby, SmartRecruiters and Workday into one clean, deduplicated feed with salary, seniority and remote flags. Turn on 'Only new jobs' to get just what was posted since your last run.

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

## Pricing

$3.00 / 1,000 job saveds

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

## Career Site Jobs Feed: Greenhouse, Lever, Ashby, SmartRecruiters, Workday

Get every open job from company career sites in one clean, deduplicated feed. Paste career-site links, and you get one row per job with the same fields for every company, whichever applicant-tracking system it uses.

### What you get

- **Five systems, one format.** Greenhouse, Lever, Ashby, SmartRecruiters and Workday, normalized into the same fields.
- **Salary.** Taken from the listing when the company publishes it (Lever, Ashby), otherwise read from the job description (for example "$150,000 - $190,000"), with currency and hourly, monthly or yearly interval.
- **Seniority.** Intern, junior, mid, senior, staff, principal, lead, director or executive, detected from the title.
- **Remote flag and workplace type.**
- **No duplicates.** A job posted once per city becomes one row with all its locations.
- **Only new jobs.** Turn on "Only new jobs since the last run" and schedule the Actor daily to get a feed of fresh openings. Jobs cut off by your limits come back on the next run instead of being lost.
- **No size cap.** Large Workday sites are paged through fully; use "Max jobs per company" or "Workday search text" to narrow them.

### Input

| Field | Example |
|---|---|
| Career site URLs | `https://boards.greenhouse.io/stripe`, `https://jobs.lever.co/palantir`, `https://jobs.ashbyhq.com/ramp`, `https://jobs.smartrecruiters.com/Visa`, `https://nvidia.wd5.myworkdayjobs.com/NVIDIAExternalCareerSite` |
| Title keywords | `engineer`, `designer` |
| Locations | `London`, `United States`, `Remote` |
| Remote jobs only | on or off |
| Seniority | `senior`, `staff` |
| Posted within (days) | `7` |
| Only jobs with a salary | on or off |
| Only new jobs since the last run | on or off |

You can also write a company as `greenhouse:stripe`, `lever:palantir`, `ashby:ramp` or `smartrecruiters:Visa`.

### Output

```json
{
  "id": "greenhouse:acme:42",
  "provider": "greenhouse",
  "companySlug": "acme",
  "companyName": "Acme",
  "title": "Senior Backend Engineer",
  "department": "Engineering",
  "locations": ["Remote - US", "New York, NY"],
  "isRemote": true,
  "workplaceType": "remote",
  "seniority": "senior",
  "salaryMin": 150000,
  "salaryMax": 190000,
  "salaryCurrency": "USD",
  "salaryInterval": "year",
  "salarySource": "description",
  "postedAt": "2026-10-01T13:00:00.000Z",
  "url": "https://boards.greenhouse.io/acme/jobs/42",
  "applyUrl": "https://boards.greenhouse.io/acme/jobs/42",
  "scrapedAt": "2026-10-17T10:00:00.000Z"
}
```

Each run also saves a `SUMMARY` record with how many jobs each career site returned, and any site that failed.

### Pricing

You pay per job saved. Filters run before saving, so jobs you filter out cost nothing, and with "Only new jobs" turned on you pay only for new openings.

### Good to know

- Only public career-site data is read: the same job feeds these systems publish for companies to embed on their own websites. No logins and no personal data.
- Workday shows dates as "Posted 3 Days Ago", so Workday dates are approximate to the day. Workday does not include descriptions in its list, so salary is not parsed there.
- Salary from descriptions is read with pattern rules. It catches the common formats, but check it before relying on it for pay benchmarks.

### Use cases

- A daily feed of new roles at a list of target companies.
- Hiring signals for sales teams: which companies are hiring for which teams.
- Job boards and newsletters that need clean, deduplicated listings.
- Salary benchmarking from published pay ranges.

# Actor input Schema

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

One link per company. Supported: boards.greenhouse.io/<company>, jobs.lever.co/<company>, jobs.ashbyhq.com/<company>, jobs.smartrecruiters.com/<company>, <company>.wd5.myworkdayjobs.com/<site>. You can also write greenhouse:stripe or lever:palantir.

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

Keep jobs whose title contains any of these words, for example engineer or designer. Leave empty for all jobs.

## `excludeKeywords` (type: `array`):

Drop jobs whose title contains any of these words.

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

Keep jobs whose location contains any of these, for example London, US or Remote.

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

Keep only jobs marked remote by the company, or with Remote in the location.

## `seniority` (type: `array`):

Keep only these levels. Detected from the job title.

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

Keep jobs posted in the last N days. Jobs with no posted date are kept.

## `salaryOnly` (type: `boolean`):

Keep only jobs that show a salary range.

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

Return only jobs you have not received before. Use it with a schedule to get a daily feed of new openings.

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

Keeps separate 'only new' memory for different feeds. Use a different name for each schedule.

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

Adds the description as plain text. Makes the output larger.

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

Stop reading a career site after this many jobs. Useful for very large Workday sites.

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

Stop after saving this many jobs. Leave empty for no limit.

## `workdaySearchText` (type: `string`):

Optional search sent to Workday sites, which can hold tens of thousands of jobs.

## Actor input object example

```json
{
  "companies": [
    "https://boards.greenhouse.io/stripe",
    "https://jobs.lever.co/palantir",
    "https://jobs.ashbyhq.com/ramp"
  ],
  "remoteOnly": false,
  "salaryOnly": false,
  "onlyNew": false,
  "stateKey": "default",
  "includeDescription": false,
  "maxJobsPerCompany": 5000
}
```

# Actor output Schema

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

All jobs from this run, as a table

## `summary` (type: `string`):

Per-company counts and errors for this run

# 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://boards.greenhouse.io/stripe",
        "https://jobs.lever.co/palantir",
        "https://jobs.ashbyhq.com/ramp"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("tillwork/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 = { "companies": [
        "https://boards.greenhouse.io/stripe",
        "https://jobs.lever.co/palantir",
        "https://jobs.ashbyhq.com/ramp",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("tillwork/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 '{
  "companies": [
    "https://boards.greenhouse.io/stripe",
    "https://jobs.lever.co/palantir",
    "https://jobs.ashbyhq.com/ramp"
  ]
}' |
apify call tillwork/ats-jobs-feed --silent --output-dataset

```

## MCP server setup

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