# Career Site Jobs Search API: Greenhouse, Lever, Ashby & Workday (`signalscouter/career-site-jobs-search`) Actor

Keyword search across thousands of company career sites at once. Find every 'data engineer' (or any role) job on Greenhouse, Lever, Ashby and Workday boards, live, with salaries, posting dates, remote and country filters and new-job alerts.

- **URL**: https://apify.com/signalscouter/career-site-jobs-search.md
- **Developed by:** [Signal Scout](https://apify.com/signalscouter) (community)
- **Categories:** Jobs, Lead generation
- **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?

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 Search API: Greenhouse, Lever, Ashby & Workday

**Search for jobs by keyword across thousands of company career sites at once.** Type "data engineer", "account executive" or "registered nurse" and get every matching opening posted on the Greenhouse, Lever, Ashby and Workday career sites in our index, read live at run time, with salaries where published, posting dates, country, remote flag and apply links.

You don't need to know which companies are hiring or which applicant tracking system (ATS) they use. The Actor ships with an index of **about 12,000 live company job boards** (around 4,500 Greenhouse, 3,300 Ashby, 4,100 Workday career sites and a small set of Lever boards, together listing roughly a million open jobs when the index was built). It searches all of them for your keywords in one run.

### Who it's for

- **Job boards and aggregators** backfilling fresh listings straight from employers' own career sites.
- **Recruiters and staffing agencies** looking for every company hiring a given role, in a given country or remote.
- **Sales and RevOps teams** using "this company is hiring X" as a buying signal. Turn on company summaries to get one hiring-signal row per company.
- **AI agents and job-matching apps** that need a daily feed of new roles via the API.

### What makes it different

- **Search, not scraping one company at a time.** Most ATS scrapers need you to paste board URLs. This one starts from keywords and finds the companies for you.
- **Live, not a stale database.** Every board is read at run time from its official public job feed, so closed jobs don't linger.
- **New-job alerts.** Turn on **Only new jobs**, schedule a daily run, and each run returns only roles this search hasn't returned before.
- **Filters that matter for hiring data:** exclude keywords, locations, ISO country codes, remote only, posted within N hours, and a per-company cap.
- **One schema across four ATSes**, the same field names as our other jobs Actors, so you can merge the outputs.
- **Company hiring summaries (optional):** open jobs on the board, jobs posted in the last 7 and 30 days, remote share, top departments and locations.

### How to use it

1. Enter one or more **keywords**. A job matches when a keyword appears at the start of a word in its title, so `engineer` also matches "Engineering Manager". Switch **Match keywords in** to *Title and description* for skills like `kafka`; it is slower.
2. Add filters: **exclude keywords**, **locations** (any text such as `London` or `Remote`), **countries** (`US`, `GB`, `DE`…), **remote only**, **posted within (hours)**.
3. Optionally limit the search to some ATSes, add your own **extra companies** (board URLs), or set **max index boards** for a quick test.
4. Set **max jobs** (default 1,000) and, for sales lists, **max jobs per company**.
5. For alerts, turn on **Only new jobs**, give the search a **monitor ID**, and schedule it daily.

#### Example input

```json
{
  "keywords": ["data engineer", "analytics engineer"],
  "excludeKeywords": ["intern"],
  "countries": ["US", "CA"],
  "postedWithinHours": 72,
  "maxResults": 500,
  "includeCompanySummary": true
}
```

#### Example job row (shortened)

```json
{
  "recordType": "job",
  "ats": "ashby",
  "companyName": "Ramp",
  "title": "Senior Data Engineer",
  "location": "New York, NY (HQ)",
  "country": "US",
  "isRemote": false,
  "workplaceType": "Hybrid",
  "employmentType": "Full-time",
  "salaryMin": 190000,
  "salaryMax": 260000,
  "salaryCurrency": "USD",
  "salaryInterval": "year",
  "salarySource": "ats",
  "postedAt": "2026-10-18T14:02:11+00:00",
  "jobUrl": "https://jobs.ashbyhq.com/ramp/…",
  "applyUrl": "https://jobs.ashbyhq.com/ramp/…/application",
  "matchedKeywords": ["data engineer"],
  "uid": "a52c6e14faf1affe"
}
```

Error rows (`recordType: "error"`) explain anything that couldn't be read, such as a bad board URL you supplied or a site whose robots.txt disallows its job feed. **Error rows are never charged.** A `RUN_SUMMARY` record in the run's key-value store shows how many boards were checked, why the run stopped and how many requests were made.

### Good to know

- **Coverage.** The index was built from the open [Common Crawl](https://commoncrawl.org) URL index (four 2026 crawls) and every board was checked against its ATS before being included. Boards with no open jobs at build time were left out to keep runs fast. We refresh it regularly. Lever is thinly covered because Common Crawl rarely crawls Lever boards; add any Lever company you care about under **Extra companies**.
- **Workday** sites are searched with Workday's own (relevance-ranked) search box, so we read up to 3 pages per keyword per site and stop at the first page with no title match. Workday only shows day-level dates ("Posted 3 Days Ago"), so `postedAt` is approximate there and summaries cover the searched jobs, not the whole site. For a full listing of specific Workday employers, use our [Workday Jobs Scraper](https://apify.com/signalscouter/workday-jobs-scraper).
- **Run time.** A search across the whole index takes several minutes because we read each employer politely (see below). Use **max index boards** or limit **ATS** for quicker runs. Runs stop cleanly before their timeout and save their progress.
- **Only new jobs.** Seen jobs are remembered per monitor ID in a key-value store in your own account. Jobs cut off by **max jobs** or your spending limit are **not** marked as seen, so they are returned next time. Progress is saved during the run, so a run that times out never returns or charges the same job twice. Daily scheduling is plenty for most searches.
- **Posting dates.** With **posted within (hours)** set, jobs that have no posting date are dropped.

### Pricing

PRICING_SECTION

### Respectful and legal use

- Only official, public, unauthenticated job-board endpoints are used: Greenhouse's Job Board API, Lever's Postings API, Ashby's public Posting API (`api.ashbyhq.com`; we never call the `/api/` paths that `jobs.ashbyhq.com/robots.txt` disallows) and the JSON feed each Workday career page itself uses.
- robots.txt is checked for Workday hosts, and Lever's crawl delay of 1 second is respected. Sites that disallow access are skipped with a free error row.
- Requests are rate-limited per host (one at a time per Workday employer), back off on HTTP 429/5xx, and stop calling a host that keeps failing. No proxies, no browser, no login, no attempt to get around blocks.
- Every request identifies itself as `signalscouter-career-jobs-search` with our contact address.
- The output is job advertisements only. No personal data about applicants or employees is collected.

### Related signalscouter Actors

| Actor | What it gives you |
|---|---|
| [Career Site Jobs Scraper](https://apify.com/signalscouter/career-site-jobs-scraper) | All jobs from specific companies across 12 ATSes (Greenhouse, Lever, Ashby, Workday, Workable and more), starting from company domains |
| [Workday Jobs Scraper](https://apify.com/signalscouter/workday-jobs-scraper) | Full listings from any `myworkdayjobs.com` career site, including sites with more than 2,000 jobs |
| [Greenhouse Jobs Scraper](https://apify.com/signalscouter/greenhouse-jobs-scraper) | Greenhouse boards with departments, offices, custom fields and pay ranges |
| [Ashby & Lever Jobs Scraper](https://apify.com/signalscouter/ashby-lever-jobs-scraper) | Startup jobs with structured compensation from Ashby and Lever |
| [UK Public Sector Jobs Scraper](https://apify.com/signalscouter/uk-public-sector-jobs-scraper) | NHS Jobs, Teaching Vacancies and DWP Find a Job |
| [Company Tech Stack & Domain Signals](https://apify.com/signalscouter/company-tech-stack-signals) | What a hiring company's website runs on, plus DNS, email security and domain age |
| [SEC Form D Funding Signals](https://apify.com/signalscouter/sec-form-d-funding-signals) | Newly funded US companies: pair "raised money" with "hiring data engineers" |
| [US Federal Contracts & Awards Signals](https://apify.com/signalscouter/us-federal-contracts-signals) | SAM.gov opportunities with incumbent award history, plus Grants.gov |

### Support and contact

Questions, missing companies or feature requests: open an issue on the Actor's **Issues** tab or email **signalscouter.data@gmail.com**.

### Changelog

- **0.1** (October 2026): first release. Keyword search across about 12,000 Greenhouse, Ashby, Workday and Lever boards; filters; company summaries; new-job monitoring with mid-run state saving.

# Actor input Schema

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

Job titles or phrases to search for, e.g. 'data engineer', 'account executive', 'nurse'. A job matches if any keyword appears at the start of a word in its title (so 'engineer' also matches 'Engineering'). Required unless you list companies.

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

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

## `searchIn` (type: `string`):

Where keywords must appear. Workday sites are always searched with Workday's own search box, then matched here.

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

Keep jobs whose location text contains any of these, e.g. 'London', 'New York', 'Germany', 'Remote'.

## `countries` (type: `array`):

Keep jobs in these countries, as 2-letter codes such as US, GB, DE. The country is read from the ATS where it gives one, otherwise guessed from the location text; jobs with no recognisable country are dropped when this is set.

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

Keep only jobs marked remote.

## `postedWithinHours` (type: `integer`):

Keep jobs first posted in the last N hours, e.g. 24, 72 or 168 (0 = any age). Jobs without a posting date are dropped when this is set. Workday only gives day-level dates ('Posted 3 Days Ago'), so its dates are approximate.

## `ats` (type: `array`):

Which job-board platforms to search. Leave empty for all four.

## `useBuiltInIndex` (type: `boolean`):

Search every company board in our bundled index (thousands of employers found in the open Common Crawl web index and checked against each ATS). Turn off to search only the companies you list below.

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

Optional. Board or job URLs to search as well, e.g. https://job-boards.greenhouse.io/stripe, https://jobs.lever.co/acme, https://jobs.ashbyhq.com/Ramp, https://nvidia.wd5.myworkdayjobs.com/NVIDIAExternalCareerSite, or 'greenhouse:stripe'. These are always read, and errors for them are reported as free error rows.

## `maxBoards` (type: `integer`):

Check only the N largest boards from the index (0 = all). Lower it for quicker test runs.

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

Stop after this many jobs (0 = no limit). Your maximum cost per run is always respected too.

## `maxResultsPerCompany` (type: `integer`):

Keep at most this many matching jobs per company (0 = no limit). Useful for sales lists.

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

Add the plain-text job description (Greenhouse, Lever and Ashby). Bigger rows, same price.

## `includeCompanySummary` (type: `boolean`):

One extra row per company with matching jobs: open jobs on the board, jobs posted in the last 7 and 30 days, remote share, top departments and locations. Charged as a separate company-summary event.

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

Return only jobs this search hasn't returned before. Seen jobs are remembered in a key-value store in your account, keyed by the monitor ID. Jobs cut off by 'Max jobs' or your spending limit are not marked as seen, so they come back next time.

## `monitorId` (type: `string`):

Name for this saved search's memory, e.g. 'data-eng-uk'. Leave empty to derive one from the keywords and filters (changing them then starts a fresh monitor).

## `workdayMaxPagesPerKeyword` (type: `integer`):

Workday search results are relevance-ranked, 20 per page. We read up to this many pages per keyword per site and stop early at the first page with no title match.

## Actor input object example

```json
{
  "keywords": [
    "data engineer"
  ],
  "searchIn": "title",
  "remoteOnly": false,
  "useBuiltInIndex": true,
  "maxBoards": 0,
  "maxResults": 1000,
  "maxResultsPerCompany": 0,
  "includeDescription": false,
  "includeCompanySummary": false,
  "onlyNew": false,
  "workdayMaxPagesPerKeyword": 3
}
```

# Actor output Schema

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

Matching job postings (recordType=job).

## `companySummaries` (type: `string`):

recordType=companySummary rows (opt-in).

## `errors` (type: `string`):

recordType=error rows. Never charged.

## `runSummary` (type: `string`):

RUN_SUMMARY: boards checked, stop reason, HTTP requests.

# 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 = {
    "keywords": [
        "data engineer"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("signalscouter/career-site-jobs-search").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 = { "keywords": ["data engineer"] }

# Run the Actor and wait for it to finish
run = client.actor("signalscouter/career-site-jobs-search").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 '{
  "keywords": [
    "data engineer"
  ]
}' |
apify call signalscouter/career-site-jobs-search --silent --output-dataset

```

## MCP server setup

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

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/ffeMdBC9a8qNdu8Xt/builds/4O9caXhMpioB8cWQN/openapi.json
