# Workday Jobs Scraper & API (`codeclouds/workday-jobs-api`) Actor

Scrape Workday job boards by career-site URL or company name. Normalized jobs with locations, country, seniority, function, salary, absolute posting dates, new/closed detection and an optional hiring profile. Jobs-only or profiles-only modes. $1 per 1,000 jobs.

- **URL**: https://apify.com/codeclouds/workday-jobs-api.md
- **Developed by:** [Dennis](https://apify.com/codeclouds) (community)
- **Categories:** Jobs, Lead generation
- **Security:** Limited permissions
- **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

## Workday Jobs Scraper & API

Scrape any public Workday career site by URL or company name and get clean, normalized job postings — plus an optional company hiring profile with new and closed roles since the previous run.

Workday powers the careers pages of thousands of large employers. Every one of those pages loads its jobs from the same public, keyless JSON endpoint. This Actor uses that endpoint directly: no browser, no login, no proxy, no API key. Pass a Workday career-site URL such as `https://nvidia.wd5.myworkdayjobs.com/NVIDIAExternalCareerSite`, or a company name such as `NVIDIA` or `Boeing`, and the Actor returns every open posting it can read.

Live on Apify: https://apify.com/CodeClouds/workday-jobs-api

### What you get

- **Job records** — title, company, tenant and career-site name, Workday req id, location(s), parsed ISO country, workplace type (remote / hybrid / onsite), employment type, seniority, job function, absolute posting date where available, the original relative label (`Posted Today`, `Posted 30+ Days Ago`), days open, the public job URL and the original apply URL.
- **New and closed roles** — the Actor keeps a snapshot per board. On the next run every job is marked `isNew`, and the company profile reports which roles disappeared.
- **Company hiring profile** (optional) — open roles by function, seniority, country and location, leadership openings, a 0–100 hiring-momentum score and human-readable signals.
- **Full descriptions and salary** (optional) — one extra request per delivered job fetches the full description and Workday's absolute `startDate`. Salary ranges are extracted from a sentence that actually mentions salary, including the `240,000 USD - 379,500 USD` style.
- **Filtering** — Workday-native keyword search plus client-side title, country, workplace, function, seniority, posted-within-days and only-new filters.

### Three ways to run

| `outputMode` | Dataset | Charged |
|---|---|---|
| `jobs_and_profiles` | One profile per employer plus filtered job records | `company-profile` + `job-result` (+ `job-description` if enabled) |
| `jobs_only` | Job records only | `job-result` (+ `job-description` if enabled) |
| `profiles_only` | One profile per employer, no job records | `company-profile` only |

`profiles_only` is the cheapest way to watch many employers: the Actor still reads each full board, so new/closed roles and momentum stay accurate, but it stores no job records.

### Input

| Field | Type | Default | What it does |
|---|---|---|---|
| `careerSiteUrls` | array of strings | Workday's own board URL | Direct Workday career-site URLs. Fastest and most precise: no detection, no guessing. A company careers-page URL also works when that page links to Workday. |
| `companies` | array of strings | `[]` | Company names or domains. Bundled verified employers resolve instantly; other names are resolved from the company's careers page. |
| `outputMode` | enum | `jobs_and_profiles` | `jobs_and_profiles`, `jobs_only` (no profile charge) or `profiles_only` (hiring signals without job records; ideal for monitoring many employers cheaply). |
| `searchText` | string | `""` | Keyword filter passed to Workday's own search (matches titles and descriptions), e.g. `engineer`, `finance`, `remote`. |
| `titleKeywords` | array of strings | `[]` | Client-side title filter. A job matches when its title contains any of these words. |
| `countries` | array of strings | `[]` | ISO-2 codes or country names, e.g. `NL`, `DE`, `United States`. Matched against the parsed country and the location text. |
| `workplaceTypes` | enum array | `[]` | Only `remote`, `hybrid` or `onsite` jobs. Unknown workplace types are excluded when this filter is active. |
| `functions` | enum array | `[]` | Normalized job functions: engineering, data_ai, product, design, sales, marketing, customer_success, operations, finance, people_hr, legal_compliance, other. |
| `seniorities` | enum array | `[]` | intern, junior, mid, senior, staff_principal, lead, manager, director, vp, executive. |
| `postedWithinDays` | integer | `0` | Only jobs posted in the last N days. `0` = no limit. Open-ended `30+ Days Ago` jobs are excluded when this filter is active. |
| `onlyNew` | boolean | `false` | Return only jobs that were not present in the previous run. The first run is the baseline and returns everything. |
| `includeDescription` | boolean | `false` | Fetch the full description and absolute posting date from Workday's per-posting detail endpoint. Adds one request and one PPE event per description. |
| `maxJobsPerCompany` | integer | `200` | Maximum job records delivered per board after filtering. The full board is still read for the profile and change detection. |
| `maxBoards` | integer | `50` | Safety cap on the number of companies/URLs processed in one run. Extra inputs are skipped and reported in the run log. |

At least one of `careerSiteUrls` or `companies` is required. The Actor fails fast with a clear message otherwise. `outputMode: "profiles_only"` is the cheapest way to monitor many employers: it still reads each full board, so new/closed counts and momentum are accurate, but it stores no job records.

### Example output

```json
{
  "recordType": "job",
  "jobKey": "workday:nvidia/NVIDIAExternalCareerSite:JR2027714",
  "company": "NVIDIA",
  "tenant": "nvidia",
  "site": "NVIDIAExternalCareerSite",
  "jobId": "JR2027714",
  "reqId": "JR2027714",
  "title": "Federal Program Director",
  "location": "US, DC, Remote",
  "country": "US",
  "workplaceType": "remote",
  "employmentType": "full_time",
  "seniority": "director",
  "jobFunction": "other",
  "publishedAt": "2026-10-30T00:00:00.000Z",
  "postedText": "Posted Today",
  "postedDatePrecision": "exact",
  "daysOpen": 0,
  "isNew": null,
  "firstSeenAt": "2026-10-30T00:00:00.000Z",
  "url": "https://nvidia.wd5.myworkdayjobs.com/NVIDIAExternalCareerSite/job/US-DC-Remote/Federal-Program-Director_JR2027714",
  "applyUrl": "https://nvidia.wd5.myworkdayjobs.com/NVIDIAExternalCareerSite/job/US-DC-Remote/Federal-Program-Director_JR2027714",
  "salaryMin": 240000,
  "salaryMax": 379500,
  "salaryCurrency": "USD",
  "salaryPeriod": "year",
  "salarySource": "description",
  "scrapedAt": "2026-10-30T13:17:35.554Z"
}
```

The optional `company_profile` record adds `openJobs`, `jobsPostedLast7Days`, `jobsPostedLast30Days`, `newJobsSinceLastRun`, `closedJobsSinceLastRun`, `netChangeSinceLastRun`, `hiringMomentum`, `hiringMomentumScore`, `topFunction`, `jobsByFunction`, `jobsBySeniority`, `countries` and the run history. Workday's board list has no salary, so the profile's salary fields stay `null`; per-job salary is filled from the description when `includeDescription` is on.

### Use cases

- **Recruiting and sourcing** — pull every open role from a list of target employers into one schema, with country, seniority and function already normalized.
- **Job boards and newsletters** — build a Workday-only feed and use `onlyNew` on a schedule to publish only fresh roles.
- **Sales and account intelligence** — hiring is a buying signal. Track whether a target account is growing engineering, sales or compliance teams, and which roles closed.
- **Compensation research** — collect disclosed salary ranges across employers and countries without reading hundreds of careers pages by hand.
- **AI agents and RAG pipelines** — feed clean job records with stable ids and URLs into an agent or vector store. The Actor is available as an MCP tool.

### How it works

1. Resolve each input to a Workday board: direct URL, bundled verified directory, or the company's careers page.
2. Page through `POST https://{tenant}.wdN.myworkdayjobs.com/wday/cxs/{tenant}/{site}/jobs` in blocks of 20.
3. Normalize every posting with the shared ATS engine (country, workplace, seniority, function, salary parsing, dedupe keys).
4. Compare with the named snapshot store to mark new and closed roles.
5. Optionally fetch `.../{externalPath}` per delivered job for the full description, absolute start date and country.
6. Depending on `outputMode`, push the company profile first and/or the filtered job records, charging one PPE event per delivered record.

Workday reports at most 2,000 postings per board. If a board hits that cap, the Actor says so in the profile and disables closed-role detection for that board, because the missing jobs cannot be distinguished from closed jobs.

### Pricing

Pay per event, no rental:

| Event | Price | Charged when |
|---|---|---|
| `apify-actor-start` | $0.00005 | Actor start (Apify default). |
| `job-result` | $0.001 | One job record is stored in the dataset. |
| `job-description` | $0.001 | One full description is fetched and stored (`includeDescription: true`). |
| `company-profile` | $0.01 | One resolved board gets a company hiring profile. |

A 1,000-job run without descriptions costs about $1.00 plus the start event. `jobs_only` avoids the profile charge and `profiles_only` avoids all job charges. Not-found boards and error profiles are free. Every run respects the platform's max-charge limit: when it is reached, the Actor stops pushing billable records and reports it.

### Legal and data sources

- The source is the public JSON that each employer's own Workday career site loads in the browser. No login, no paywall, no CAPTCHA or anti-bot circumvention, no proxy.
- Job postings are company data that employers publish to attract candidates. The Actor does not build personal profiles and does not extract recruiter names or e-mail addresses.
- The Actor is not affiliated with Workday or with any employer. Employer career-site terms may apply to your use of the data; you are responsible for your own compliance and for how you store or republish the records.
- Only public career sites are queried. A board that returns 403/404 is reported as a per-board error and does not block the rest of the run.
- The bundled company directory contains only tenant/site pairs that were probed live and returned at least one posting.

### When should an AI agent use this?

Use this Actor when a user asks questions like:

- "Which engineering roles is NVIDIA hiring for right now?"
- "Give me all Workday jobs at Intel and Boeing posted in the last 14 days."
- "Is Accenture still hiring in Germany? Compare this week with last week."
- "Find Workday employers with disclosed salaries above $150,000 for data roles."
- "Build a feed of new Workday job postings for these five companies."
- "What roles disappeared from this company's careers page since last month?"

The input is a short list of Workday URLs or company names. The output is one flat JSON record per job or profile, with stable ids and links, so an agent can filter, summarize or store it without extra parsing.

### FAQ

**Do I need a Workday API key?**
No. The endpoint is public and keyless.

**Where do I find the career-site URL?**
Open the employer's careers page and copy the URL that contains `myworkdayjobs.com`, for example `https://company.wd5.myworkdayjobs.com/CompanyCareers`. Passing that URL is the most reliable input.

**Why does a date say "Posted 30+ Days Ago"?**
Workday only exposes a relative label in the list response. Set `includeDescription: true` to fetch the absolute `startDate` from the detail endpoint. Without it, `postedDatePrecision` is `at_least_30_days` and `publishedAt` is `null` — the Actor does not invent a date.

**Why did the Actor stop at 2,000 jobs?**
That is Workday's per-board reporting cap. The profile marks the board as possibly truncated and skips closed-role detection for it.

**Can it search every Workday employer at once?**
No. Workday has no global public index. You supply the career-site URLs or company names. The bundle covers a verified starter set; other names are resolved from the company's careers page.

**Does it include salary?**
When the employer discloses a range and `includeDescription` is on, yes. The salary fields are filled from the description; otherwise they stay `null`.

**How does `onlyNew` work?**
The Actor stores a snapshot per board in a named key-value store. The first run is the baseline. Later runs mark jobs that were not in the previous snapshot. Schedule the Actor (for example daily) to get a meaningful signal.

**Are closed jobs returned as records?**
Closed jobs are summarized in the company profile (`closedJobsSinceLastRun` and `closedJobTitles`), not emitted as job records.

**How do I monitor many employers cheaply?**
Set `outputMode: "profiles_only"`. The Actor still reads each full Workday board and computes new/closed roles, momentum and counts, but stores only one profile per employer ($0.01 each) and no job records.

**Can I get only fresh jobs for a job board?**
Yes. Use `outputMode: "jobs_only"`, `onlyNew: true` and a daily schedule. The first run is the baseline; later runs return only postings that were not in the previous snapshot.

**What happens when one board is unavailable?**
The error is reported as a free error profile for that input and the remaining boards continue.

### Keywords

Workday jobs API, Workday scraper, scrape Workday jobs, Workday career site, Workday job board, Workday jobs by company, Workday job postings, ATS job scraper, job board API, hiring signals, new job alerts, salary data, recruiting data, job market data.

### Related Actors

- [Career Sites ATS Job Feed & Company Hiring Signals](https://apify.com/CodeClouds/career-sites-ats-jobfeed) — the multi-ATS version (Greenhouse, Lever, Ashby, Workday, Workable, Recruitee, SmartRecruiters, Personio) with company detection. Use this Workday Actor when you want a dedicated Workday listing, Workday-native search and the detail endpoint.

### Changelog

- **0.1** (2026-10-30) — initial version: Workday board resolution by URL, bundled verified directory or careers page; paging with req-id dedupe and run deadline; normalized jobs; relative-date precision; optional detail fetch with absolute date, description and salary extraction; new/closed snapshots; company hiring profile; `jobs_and_profiles`/`jobs_only`/`profiles_only` modes; title, country, workplace, function, seniority, posted-within and only-new filters; `maxBoards` safety cap; PPE pricing.

### Changelog policy

This Actor follows semantic versioning for its input and output contract. New optional fields are additive; removing or renaming a field is a breaking change and gets a new minor version with a release note.

# Actor input Schema

## `careerSiteUrls` (type: `array`):

Direct Workday career-site URLs, one per line, e.g. https://nvidia.wd5.myworkdayjobs.com/NVIDIAExternalCareerSite. This is the fastest and most precise input: no detection or guessing. A company careers-page URL also works when that page links to Workday.

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

Company names or domains, one per line (e.g. NVIDIA, intel.com, Boeing). Bundled verified Workday employers resolve instantly; other names are resolved from the company's careers page. Use careerSiteUrls when the URL is known.

## `outputMode` (type: `string`):

Jobs and profiles (default), jobs only (no $0.01 profile charge), or profiles only (hiring signals without job records; ideal for monitoring many employers cheaply).

## `searchText` (type: `string`):

Optional keyword filter passed to Workday's own search (matches titles and descriptions), e.g. engineer, finance, remote. Leave empty for the full board.

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

Client-side title filter, one or more words (e.g. engineer, director). A job matches when its title contains any of these words. Use searchText for Workday's server-side search across titles and descriptions.

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

Only return jobs in these countries, as ISO-2 codes or names (e.g. NL, DE, United States). Matched against the parsed country and the location text. Leave empty for all countries.

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

Only return remote, hybrid or onsite jobs. Workday exposes this for many postings; unknown workplace types are excluded when this filter is active. Leave empty for all.

## `functions` (type: `array`):

Only return jobs in these normalized functions. Leave empty for all.

## `seniorities` (type: `array`):

Only return jobs at these seniority levels (inferred from the title, with the ATS level as fallback). Leave empty for all.

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

Only return jobs posted in the last N days. 0 means no limit. Workday shows 'Posted 30+ Days Ago' without an exact date: those jobs are excluded when this filter is active (they are included when it is 0).

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

Return only postings that were not present in the previous run of this Actor. On the first run every job is the baseline and is returned. Schedule this Actor for a meaningful new/closed signal.

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

Fetch the full job description and absolute posting date from Workday's per-posting detail endpoint. Adds one request per delivered job and costs one extra PPE event per description.

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

Maximum number of job records delivered per board after filtering. The full board is still read for the company profile and change detection. Large Workday boards can contain 2000+ postings.

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

Safety cap on the number of companies/URLs processed in one run. Extra inputs are skipped and reported in the run log, which keeps large pasted lists and accidental cost predictable.

## Actor input object example

```json
{
  "careerSiteUrls": [
    "https://nvidia.wd5.myworkdayjobs.com/NVIDIAExternalCareerSite"
  ],
  "companies": [
    "NVIDIA"
  ],
  "outputMode": "jobs_and_profiles",
  "searchText": "software engineer",
  "titleKeywords": [
    "engineer"
  ],
  "countries": [
    "NL"
  ],
  "workplaceTypes": [
    "remote"
  ],
  "functions": [
    "engineering"
  ],
  "seniorities": [
    "senior"
  ],
  "postedWithinDays": 14,
  "onlyNew": false,
  "includeDescription": true,
  "maxJobsPerCompany": 200,
  "maxBoards": 50
}
```

# Actor output Schema

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

Job postings and company profiles in the default dataset.

# 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 = {
    "careerSiteUrls": [
        "https://workday.wd5.myworkdayjobs.com/Workday"
    ],
    "companies": [],
    "titleKeywords": [],
    "countries": []
};

// Run the Actor and wait for it to finish
const run = await client.actor("codeclouds/workday-jobs-api").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 = {
    "careerSiteUrls": ["https://workday.wd5.myworkdayjobs.com/Workday"],
    "companies": [],
    "titleKeywords": [],
    "countries": [],
}

# Run the Actor and wait for it to finish
run = client.actor("codeclouds/workday-jobs-api").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 '{
  "careerSiteUrls": [
    "https://workday.wd5.myworkdayjobs.com/Workday"
  ],
  "companies": [],
  "titleKeywords": [],
  "countries": []
}' |
apify call codeclouds/workday-jobs-api --silent --output-dataset

```

## MCP server setup

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

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/cWTHRJajDeupYA6EB/builds/AV3b17Z7xnSVmxBsF/openapi.json
