# Career Site Jobs: Workday, Greenhouse, Lever, Ashby & 6 more (`wiltech/career-site-jobs`) Actor

Open jobs from company career sites on 10 job systems incl. Workday, Greenhouse, Lever, Ashby and Workable. Get salary, location, remote status and new-job alerts.

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

## Pricing

from $2.00 / 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.

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: Workday, Greenhouse, Lever, Ashby & 6 more

Get every open job straight from company career sites, in one clean format. Type a company name, website or job board link; the Actor finds the company's job board and returns each job with title, location, country, remote status, salary range, department, posting date and apply link.

Use it to **track who is hiring**, build **job boards and alerts**, find **sales leads from hiring signals**, research **salaries and competitors**, or give an **AI agent** live jobs data.

### What you get

- **10 job systems in one tool:** Workday, Greenhouse, Lever (including Lever EU), Ashby, SmartRecruiters, Workable, Recruitee, Personio, Teamtailor and Breezy HR, which power the career pages of thousands of companies, from startups to Salesforce, NVIDIA, Airbnb, Stripe, Hugging Face and Bosch.
- **Public job feeds only.** Data comes from each job system's public job board feed, the same data companies use to show jobs on their own career pages. No logins, no scraping around bot protection, and each Workday site's robots.txt is respected.
- **One schema for every company.** Workplace type, employment type, salary period and country are mapped to the same values whichever system the company uses.
- **Salary ranges** when the company publishes them (min, max, currency, period), including Workday pay ranges written in the job description ("$172,500 - $260,100 annually").
- **New-job alerts:** schedule the Actor daily and get only jobs that appeared since the last run.
- **Finds the board for you:** give `stripe.com` or `Discord` and it locates the right board, checks it really belongs to that company, and tells you how sure it is.
- **Never silent:** a company that can't be matched or loaded gets a free status record saying why.

### Sample output

```json
{
  "recordType": "job",
  "id": "lever:zoox:e8a190f0-7a89-4c11-a6a0-452ff6234749",
  "provider": "lever",
  "companyName": "Zoox",
  "title": "Administrative Business Partner, Floater",
  "department": "Executive Office",
  "location": "Foster City, CA",
  "locations": ["Foster City, CA"],
  "countryCode": "US",
  "workplaceType": "hybrid",
  "isRemote": false,
  "employmentType": "full-time",
  "salary": { "min": 123000, "max": 168000, "currency": "USD", "period": "year", "periodInferred": false, "text": "USD 123,000–168,000 per year" },
  "salaryMin": 123000,
  "salaryMax": 168000,
  "salaryCurrency": "USD",
  "salaryPeriod": "year",
  "salaryText": "USD 123,000–168,000 per year",
  "postedAt": "2026-10-06T17:27:44.932Z",
  "url": "https://jobs.lever.co/zoox/e8a190f0-7a89-4c11-a6a0-452ff6234749",
  "applyUrl": "https://jobs.lever.co/zoox/e8a190f0-7a89-4c11-a6a0-452ff6234749/apply",
  "description": "Zoox is building the future of transportation…",
  "matchConfidence": "exact",
  "isNew": true,
  "firstSeenAt": "2026-10-26T12:00:00.000Z",
  "scrapedAt": "2026-10-26T12:00:00.000Z"
}
```

### How to use it

1. Add companies in **Companies**, one per line, in any of these forms:
   - a name: `Discord`
   - a website: `stripe.com`
   - a job board link: `https://jobs.lever.co/palantir`, `https://jobs.ashbyhq.com/ramp`, `https://job-boards.greenhouse.io/airbnb`, `https://nvidia.wd5.myworkdayjobs.com/NVIDIAExternalCareerSite`
   - provider and board: `greenhouse:airbnb`, `lever:zoox`, `lever-eu:company`, `ashby:openai`, `smartrecruiters:BoschGroup`, `workday:salesforce`, `workable:huggingface`, `recruitee:channable`, `personio:ottonova`, `teamtailor:company`, `breezy:company`
2. Optionally narrow the results with filters.
3. Run it. Results appear in the dataset; download as JSON, CSV or Excel, or connect them to Google Sheets, Slack, Zapier or Make.

**Tip:** links and websites give the most accurate matches. A bare name works well for well-known companies; when a name is ambiguous the Actor skips uncertain boards instead of guessing, and says so in a status record.

### Filters

All filters run before results are saved, so you only pay for jobs you keep.

| Filter | Example |
| --- | --- |
| Job title contains | `engineer`, `sales` (matches the start of words: "engineer" finds "Engineering Manager") |
| Job title does not contain | `intern`, `senior` |
| Location contains | `London`, `Germany`, `Remote`, `US` |
| Workplace type | Remote, Hybrid, On-site, Not stated |
| Department or team contains | `Engineering`, `Sales` |
| Posted in the last N days | `7` |
| Only jobs that show a salary | on/off |

### New jobs only (alerts)

Turn on **Only new jobs since the last run** and schedule the Actor (for example every morning). The first run returns everything and sets the baseline; later runs return only jobs that weren't there before. Every job also carries `isNew` and `firstSeenAt`. Use **Watch list name** to keep separate alert lists, or to keep tracking when you add companies.

### For AI agents and automations

- Every input has a sensible default except **Companies**, which is required.
- Results never come back empty without a reason: unmatched companies, missing boards, failed loads and "no jobs matched your filters" each produce a `recordType: "status"` row with a plain-language `message`. Status rows are free.
- A run summary (per company: boards found, confidence, jobs found and saved, notes) is saved to the key-value store as `OUTPUT`.
- `matchConfidence` on every job: `exact` (you gave the board), `high` (found on the company's own website, or the board's company name matches), `medium` (board name equals the company name, but the job system doesn't publish a company name to confirm it).

### Output fields

| Field | Description |
| --- | --- |
| `id` | Stable ID: `provider:board:jobId`. Use it to deduplicate across runs. |
| `provider`, `companySlug` | Job system and the company's board name in it |
| `companyName` | Company name: from the job system when it publishes one (Greenhouse, SmartRecruiters), otherwise the name you typed or a readable form of the board name (`acme-robotics` → "Acme Robotics") |
| `title`, `department`, `team`, `seniority` | Role details, when the job system provides them |
| `location`, `locations` | Primary location and all listed locations |
| `countryCode`, `countryName` | ISO country code; from the job system, or recognized from the location text (e.g. "Lisbon, Portugal" → PT). Null when unknown or when a job spans several countries. |
| `workplaceType`, `isRemote` | `remote`, `hybrid`, `onsite` or `unspecified` |
| `employmentType` | `full-time`, `part-time`, `contract`, `internship`, `temporary`, `other` |
| `salary` | `min`, `max`, `currency`, `period` (`year`, `month`, `week`, `day`, `hour`), `periodInferred`, `text`; null when the job publishes no salary |
| `salaryMin`, `salaryMax`, `salaryCurrency`, `salaryPeriod`, `salaryText` | The same salary as flat columns, handy for spreadsheets and CSV |
| `postedAt`, `updatedAt` | ISO dates |
| `url`, `applyUrl` | Job page and application link |
| `requisitionId` | Company's internal requisition ID, when public |
| `description`, `descriptionHtml` | Full description as text and/or HTML (see **Job description**) |
| `isNew`, `firstSeenAt` | New-job tracking (`isNew` is null on the first run) |
| `companyInput`, `matchConfidence`, `scrapedAt` | Which input produced the job, how sure the match is, when it was collected |

### Pricing

Pay per result: **$2.00 per 1,000 jobs** saved, plus Apify's small per-run start fee. Filtered-out jobs and status records are free. Set a maximum cost per run in Apify Console and the Actor stops cleanly when it is reached.

### Good to know

- **Coverage:** companies whose careers page runs on Workday, Greenhouse, Lever, Ashby, SmartRecruiters, Workable, Recruitee, Personio, Teamtailor or Breezy HR. Companies on other systems (iCIMS, Taleo, SuccessFactors and others) return a status record saying no board was found. Use **Job systems to check** to look on fewer systems.
- **Workable, Recruitee, Personio, Teamtailor and Breezy HR** are read from their public career feeds. Personio jobs come in the language they were written in; Personio and Teamtailor publish no salary for most jobs, and Breezy's salary is the employer's own text (amounts are read from it, and the currency is only set when it is clear). Hidden Workable locations and office street addresses are never output.
- **Salaries** appear only when the company publishes them. Greenhouse does not state a pay period; it is inferred from the amounts and marked `periodInferred: true`.
- **Greenhouse and Ashby** do not provide an employment type; it is left empty rather than guessed.
- **Workday:**
  - A company name is matched by looking for its Workday site; the employer name Workday publishes confirms the match (`high`). For companies whose Workday name differs from their brand, give the career-site link.
  - Workday shows at most 2,000 jobs per search, so larger sites are read in groups (by country, job category and so on) and merged without duplicates.
  - Workday needs one extra request per job for the full posting. Title and date filters are checked first, so jobs you filter out are never opened, which keeps big runs fast.
  - Workday has no department field (so the department filter skips Workday jobs), and its salary comes from the pay range written in the description (the first range is used; some postings list a second range for high-cost cities).
  - `workplaceType` comes from Workday's own remote/office setting; "Flexible" settings are mapped to `hybrid`.
  - Employers with many career sites (for example internships or subsidiaries) are read site by site, up to 10 sites; give a site link to read just one.
- **SmartRecruiters** descriptions need one extra request per job; choose "Don't include" for descriptions to make large SmartRecruiters runs much faster.
- **Website scanning** reads at most a few pages (`/careers`, `/jobs`, the home page) and respects each site's robots.txt.
- **Privacy:** the Actor outputs job postings only. Recruiter names that some job systems include are never output.

### Support

Something missing or wrong? Open an issue on the Actor's Issues tab with the company you tried; fixes and new job systems are added based on requests.

# Actor input Schema

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

One company per line. Use a company name (Discord), a website (stripe.com), a job board link (https://jobs.lever.co/palantir, https://nvidia.wd5.myworkdayjobs.com/NVIDIAExternalCareerSite, https://apply.workable.com/huggingface) or provider:board (greenhouse:airbnb, lever:zoox, ashby:ramp, smartrecruiters:BoschGroup, workday:salesforce, workable:huggingface, recruitee:channable, personio:ottonova, teamtailor:career, breezy:company). Links and websites give the most accurate matches.

## `titleKeywords` (type: `array`):

Keep jobs whose title contains any of these words, e.g. engineer, sales, marketing. Matches the start of words, so "engineer" also finds "Engineering Manager". Leave empty for all jobs.

## `excludeTitleKeywords` (type: `array`):

Drop jobs whose title contains any of these words, e.g. intern, senior.

## `locationKeywords` (type: `array`):

Keep jobs whose location matches any of these, e.g. London, Germany, Remote, or a 2-letter country code such as US.

## `workplaceTypes` (type: `array`):

Keep only these workplace types. Leave empty for all. "Not stated" covers jobs whose posting does not say.

## `departmentKeywords` (type: `array`):

Keep jobs whose department or team matches any of these, e.g. Engineering, Sales.

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

Keep jobs posted in the last N days. 0 means any date. Jobs with no posting date are kept.

## `requireSalary` (type: `boolean`):

Keep only jobs that publish a salary range.

## `onlyNewJobs` (type: `boolean`):

Return only jobs not seen in earlier runs of the same company list (or the same watch list name). Ideal for scheduled daily or weekly alerts. The first run returns everything and sets the baseline.

## `watchListName` (type: `string`):

Optional. Give a name to keep "new job" tracking separate from your other lists, or to keep it when you edit the company list. Without a name, tracking follows the exact company list.

## `descriptionFormat` (type: `string`):

Include the full job description as plain text, HTML, both, or not at all (faster, smaller results).

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

Stop reading a company's board after this many jobs. Large employers list thousands of jobs.

## `maxTotalJobs` (type: `integer`):

Stop the run after saving this many jobs in total. 0 means no limit. Your run's spending limit is always respected as well.

## `scanCompanyWebsites` (type: `boolean`):

When you give a website (stripe.com), read its careers page to find the exact job board. Respects the site's robots.txt. Turn off to only check job systems directly.

## `acceptUncertainMatches` (type: `boolean`):

When a company name only loosely matches a job board, include it anyway. Off by default so you never get another company's jobs by mistake; every job carries matchConfidence either way.

## `jobSystems` (type: `array`):

Only look for boards on these job systems. Leave empty to check all of them. When you give a company name, Greenhouse, Lever, Ashby and SmartRecruiters are checked first, then the smaller systems, and Workday last, because those take more requests.

## `includeStatusRecords` (type: `boolean`):

Add a record (recordType "status", never charged) for each company that could not be matched or loaded, explaining why. Useful for automations and AI agents so a missing company is never silent.

## Actor input object example

```json
{
  "companies": [
    "Discord",
    "stripe.com",
    "https://jobs.lever.co/palantir",
    "https://nvidia.wd5.myworkdayjobs.com/NVIDIAExternalCareerSite",
    "ashby:ramp"
  ],
  "titleKeywords": [],
  "excludeTitleKeywords": [],
  "locationKeywords": [],
  "workplaceTypes": [],
  "departmentKeywords": [],
  "postedWithinDays": 0,
  "requireSalary": false,
  "onlyNewJobs": false,
  "watchListName": "",
  "descriptionFormat": "text",
  "maxJobsPerCompany": 500,
  "maxTotalJobs": 0,
  "scanCompanyWebsites": true,
  "acceptUncertainMatches": false,
  "jobSystems": [],
  "includeStatusRecords": true
}
```

# Actor output Schema

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

All open jobs that matched your filters, plus free status records for companies that need attention.

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

Per-company report: job boards found, match confidence, jobs found and saved, and notes.

# 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": [
        "Discord",
        "https://jobs.ashbyhq.com/linear",
        "lever:zoox"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("wiltech/career-site-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": [
        "Discord",
        "https://jobs.ashbyhq.com/linear",
        "lever:zoox",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("wiltech/career-site-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": [
    "Discord",
    "https://jobs.ashbyhq.com/linear",
    "lever:zoox"
  ]
}' |
apify call wiltech/career-site-jobs --silent --output-dataset

```

## MCP server setup

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