# Workday Jobs API - Careers Site Scraper & Hiring Feed (`apifmcpfactory/workday-jobs-api`) Actor

Every open role on any Workday careers site as structured JSON or CSV, at $1.50 per 1,000 jobs. Paste the careers URL. Title, location, country, employment type, remote type, posted date and apply link. Change detection between runs and a white-label hiring report included.

- **URL**: https://apify.com/apifmcpfactory/workday-jobs-api.md
- **Developed by:** [Howth Technology Factory](https://apify.com/apifmcpfactory) (community)
- **Categories:** Jobs, Developer tools, Agents
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

Pay per event

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/platform/actors/running/actors-in-store#pay-per-event

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
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.
Actors are written with capital "A".

## 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.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## Workday Jobs API + Report

Every open role on any Workday careers site, as clean structured data. Paste the careers URL.

**Unofficial. Not affiliated with or endorsed by Workday.**

***

### What it does

Reads the public Workday careers feed and returns one row per open role: title, location, country with its ISO code, employment type, remote type, the real posted date and the apply link. It de-duplicates, flags likely reposts without deleting them, tells you what changed since your last run, and can produce a white-label hiring report in HTML and PDF.

Workday is the largest enterprise applicant-tracking system, so this is the listing that covers big employers the smaller ATS platforms never see.

### Who it's for

- **Recruiters and sourcers** tracking large enterprise employers.
- **Market researchers** measuring hiring at scale — a single tenant here can carry thousands of open roles.
- **AI agents** needing enterprise roles as structured JSON — see the MCP block below.

### You need the careers URL, not the company name

Unlike the other listings in this family, a company name alone cannot work here. A Workday board is a triple — tenant, datacentre and site — and only the first is derivable:

```
https://nvidia.wd5.myworkdayjobs.com/NVIDIAExternalCareerSite
        ^tenant ^datacentre            ^site name
```

The datacentre is one of at least `wd1`, `wd3`, `wd5`, `wd10`, `wd12`, and the site name is arbitrary text the employer chose — `NVIDIAExternalCareerSite`, `Jobs`, `External_Career_Site`. Guessing it would just produce wrong answers, so a bare company name is refused with a message explaining exactly this rather than quietly returning nothing.

### Sample output

From a real run, 2026-08-01: **100 roles in 52 seconds**, 105 HTTP requests, no retries and no errors.

```json
{
  "source": "workday",
  "board": "redhat|wd5|Jobs",
  "company": "redhat",
  "title": "Principal Forward Deployed Engineer - AI Platform",
  "location": "Singapore",
  "country": "SG",
  "isRemote": false,
  "workplaceType": "onsite",
  "employmentType": "full-time",
  "postedAt": "2026-08-01",
  "applyUrl": "https://redhat.wd5.myworkdayjobs.com/Jobs/job/Singapore/...",
  "description": null
}
```

#### What Workday actually publishes

Measured on those same 100 roles.

| Field | Coverage | |
|---|---|---|
| `title`, `company`, `location`, `country`, `workplaceType`, `postedAt`, `applyUrl` | 100 / 100 | always present |
| `employmentType` | 97 / 100 | |
| `department`, `team`, `seniority`, `salary`, `updatedAt` | 0 / 100 | not published by Workday |

#### Two requests per role, and a 100-role cap

Workday's list response carries only a title, a path, a location string and a **relative** recency — `Posted Today`, `Posted 30+ Days Ago`. That is not a date, and converting it into one would be guessing, which this product does not do. The real posted date, the employment type, the country code and the remote type all live on a per-role detail endpoint.

So each role costs a second request, and **a board is bounded at 100 roles per run**. When a tenant has more, the run returns the newest 100 and says so in the result rather than silently truncating. Narrow with the title, location and date filters, or run one site at a time.

The list page size is fixed at 20 by the platform — `limit=50` and `limit=100` both return HTTP 400.

### The three rules this product is built on

1. **Job descriptions belong to the employer.** `includeDescription` is **off by default**.
2. **No personal data, ever.** No recruiter names, no hiring-manager contacts, no emails, no phone numbers. There is nowhere in this schema to put one, and a test fails the build if a personal-data field appears.
3. **Unofficial, reading a public feed.** No key, no login, no browser automation, no anti-bot circumvention. A live tenant's `robots.txt` expressly allows the careers-site path. Not affiliated with or endorsed by Workday.

### Pricing

| Event | Price |
|---|---|
| Actor start | $0.00005 |
| Job returned | $0.0015 |

**$1.50 per 1,000 jobs**, charged on the final de-duplicated set. A board that could not be read returns nothing and is **not charged**. The 25-job run used for the platform check cost **$0.04**.

### Monitoring

Set `onlyNewSinceLastRun` and schedule it. The first run on each board stores a baseline and returns everything — nothing is reported as a change, because everything being new the first time is not news. Add a `webhookUrl` for a JSON summary when anything moves.

### FAQ

**Do I need a Workday API key?** No. This reads the public careers feed.

**Why won't a company name work?** See above — the datacentre and site name cannot be derived. Paste the careers URL.

**Why only 100 roles per company?** Because a usable record costs a second request per role. The bound is stated in the result, not hidden.

**Why is `department` always empty?** Because Workday's public feed does not publish it. Left null rather than guessed.

**Why is `postedAt` a real date when the site says "Posted Today"?** Because the date comes from the detail endpoint. The relative phrase is never converted.

**Is it stable?** Checked across nine unrelated tenants; every correctly-formed triple answered 200. The failures were wrong site names in the test, not the API.

### MCP — for AI agents

```json
{ "mcpServers": { "jobs": { "url": "https://jobs-api.mcpize.run" } } }
```

`search_jobs` $0.01 · `get_company_jobs` $0.01 · `monitor_jobs` $0.02 · `generate_report` $0.10

***

*Unofficial. Not affiliated with or endorsed by Workday. Job adverts are the property of the employers who published them.*

# Actor input Schema

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

One per line. Paste a Workday careers URL, a careers URL, or just the company name — all three are resolved for you, so you never have to go hunting for an internal identifier. Up to 100 per run.

## `dataPreset` (type: `string`):

All jobs is right for most uses. New only is for scheduled runs. With descriptions returns the advert body as well — see the note below before switching it on.

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

Off by default, and deliberately. A job advert is the employer's copyrighted text; the structured fields are not. Leaving it off means smaller payloads, faster runs and a cleaner licence position. Switch it on when your use needs the body text.

## `onlyNewSinceLastRun` (type: `boolean`):

For scheduled runs. The first run on a board always returns everything and stores the baseline; after that you get only what appeared since. Removed and edited postings are still reported in the summary and the report.

## `titleIncludes` (type: `array`):

For example engineer, designer, product. Leave empty for every role.

## `titleExcludes` (type: `array`):

For example intern, contract. Applied after the include list.

## `locationIncludes` (type: `array`):

For example Dublin, Germany, Remote.

## `departmentIncludes` (type: `array`):

Only useful where Workday publishes one — see the platform notes in the README.

## `employmentTypes` (type: `array`):

Normalised across every platform in this family. A platform that does not publish one leaves it empty, and those jobs are excluded when you set a filter here.

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

Uses the platform's own remote flag where there is one, and the location text where there is not.

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

Leave empty for all. Jobs with no published date are kept rather than silently dropped.

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

Caps what each board can return, and therefore what it can cost. Leave empty for all of them.

## `sortBy` (type: `string`):

Undated postings always sort last rather than pretending to be the oldest.

## `generateReport` (type: `boolean`):

A client-ready review of the whole run: where the hiring is by department and location, what changed since the last run, and every open role in one table. Costs nothing extra.

## `reportFormat` (type: `string`):

HTML opens in any browser and prints cleanly to A4. PDF is ready to send to a client.

## `reportCompanyName` (type: `string`):

Appears on the report. Setting this (or a logo) puts it in white-label mode and takes our name off.

## `reportLogoUrl` (type: `string`):

A direct link to a PNG, JPG or SVG.

## `reportAccentColor` (type: `string`):

Hex colour used for headings, for example #1E3A8A.

## `reportFooterText` (type: `string`):

Appears at the bottom of every page — usually your company name or a client reference.

## `exportFormat` (type: `string`):

The dataset is always JSON. This additionally writes flat comma-separated files you can open in a spreadsheet — the jobs, the boards, and what changed.

## `webhookUrl` (type: `string`):

Called with a JSON summary when a board gains, loses or changes a posting. Nothing fires on the first run, because everything is new the first time and that is not news.

## `userAgent` (type: `string`):

Every request declares who is making it and how to reach them. The default identifies this actor. If you are running at volume, put your own company name and email here.

## `requestsPerSecond` (type: `integer`):

Shared across the whole run. The default is deliberately gentle: these are free public feeds and staying welcome on them matters more than finishing half a second sooner.

## Actor input object example

```json
{
  "companies": [
    "https://nvidia.wd5.myworkdayjobs.com/NVIDIAExternalCareerSite",
    "https://redhat.wd5.myworkdayjobs.com/Jobs",
    "https://salesforce.wd12.myworkdayjobs.com/External_Career_Site"
  ],
  "dataPreset": "all-jobs",
  "includeDescription": false,
  "onlyNewSinceLastRun": false,
  "remoteOnly": false,
  "sortBy": "newest",
  "generateReport": false,
  "reportFormat": "both",
  "reportAccentColor": "#1E3A8A",
  "exportFormat": "none",
  "userAgent": "Howth Technology Factory jobs-api apifymcpfactory@gmail.com",
  "requestsPerSecond": 4
}
```

# Actor output Schema

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

No description

## `report` (type: `string`):

No description

## `reportPdf` (type: `string`):

No description

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

No description

## `csv` (type: `string`):

No description

# 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://nvidia.wd5.myworkdayjobs.com/NVIDIAExternalCareerSite",
        "https://redhat.wd5.myworkdayjobs.com/Jobs",
        "https://salesforce.wd12.myworkdayjobs.com/External_Career_Site"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("apifmcpfactory/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 = { "companies": [
        "https://nvidia.wd5.myworkdayjobs.com/NVIDIAExternalCareerSite",
        "https://redhat.wd5.myworkdayjobs.com/Jobs",
        "https://salesforce.wd12.myworkdayjobs.com/External_Career_Site",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("apifmcpfactory/workday-jobs-api").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print("💾 Check your data here: https://console.apify.com/storage/datasets/" + run["defaultDatasetId"])
for item in client.dataset(run["defaultDatasetId"]).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://nvidia.wd5.myworkdayjobs.com/NVIDIAExternalCareerSite",
    "https://redhat.wd5.myworkdayjobs.com/Jobs",
    "https://salesforce.wd12.myworkdayjobs.com/External_Career_Site"
  ]
}' |
apify call apifmcpfactory/workday-jobs-api --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=apifmcpfactory/workday-jobs-api",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/acts/9Kz0mw3haZvFq5LjC/builds/EbjBo4O3KW0ktsSyv/openapi.json
