# Changelog of Workday Jobs Scraper (`humble-echidna/workday-jobs`) Actor

- **URL**: https://apify.com/humble-echidna/workday-jobs/changelog.md
- **Full Actor documentation**: https://apify.com/humble-echidna/workday-jobs.md

## Changelog

Versions follow MAJOR.MINOR.PATCH (`src/version.py`); Apify shows MAJOR.MINOR from `.actor/actor.json`.
Every run logs its version and records it in the `RUN_STATS` key-value record.

### 1.1.1 (2026-10-16)

- A run that returns nothing (every input bad, private, blocked or unreachable, or an empty input) now ends
  SUCCEEDED with an empty dataset and the reason as its status message and in the log, instead of FAILED. Only an
  unexpected error still fails the run. `RUN_STATS` keeps the reason as before.
- No change to output fields or price.

### 1.1.0 (2026-10-10)

**Back in service: runs read Workday career sites again.** The 1.0.1 deprecation is lifted. This is an unofficial
tool, not affiliated with Workday. It reads only what a company's Workday career site shows any visitor without
logging in (its open job postings), keeps no candidate or recruiter data, and stays inside each site's robots.txt
(the career site is allowed and the job data it reads isn't disallowed; checked on 2026-10-10 on
nvidia.wd5.myworkdayjobs.com, sonos.wd1.myworkdayjobs.com and zendesk.wd1.myworkdayjobs.com).

- Built on the current shared code, so it gains everything the other job actors got since 1.0: departments,
  employment types and minimum-salary filters, and **Also report closed and changed jobs** (a job-change feed of new,
  changed and closed jobs).
- Employment and workplace type now come from Workday's job list when the company shows them there, and from each
  job's own record otherwise. Location, remote, employment-type and salary filters read each job's record first, so
  they judge every location and the description, not just "3 Locations".
- Polite pacing: at most 4 requests in flight and about 7 a second per career site, list pages and job records
  alike (1.0 sent up to 8 at once, unpaced).
- Default input: one company, Sonos (about 50 jobs), so the first run is small and quick.
- A Workday URL pasted into another of our job actors is now pointed here.
- Every output field is described in the dataset schema, with the same text as our other job actors.

### 1.0.1 (2026-09-24)

**Deprecated: the platform's terms don't allow this use.** Workday career sites can only be read through the internal backend of Workday's own career-site web app (`/wday/cxs/…`). That isn't a documented public API or feed, and Workday's Online Terms of Service require a separate agreement for its APIs.

- Every run now exits successfully at once with that notice (status message, log and `RUN_STATS.deprecated`), fetches nothing and returns no jobs, so existing users' runs and schedules don't fail while the actor is retired from the Store.
- All Workday fetching code is removed. Company Career Page Jobs Scraper (`ats-jobs`) covers Greenhouse, Lever, Ashby, Recruitee, Personio and Teamtailor.

### 1.0.0 (2026-09-24)

First release. Workday-only edition of Company Career Page Jobs Scraper (`ats-jobs`), sharing its code
(`common/mms_ats`) and output format.

- Shared safety code (`mms_common`, the same in every actor of this portfolio): robots.txt per RFC 9309 (byte-order
  marks, product-token matching, percent-encoding, a 500 KiB cap counted while streaming), a Crawl-delay above 30 s
  reports that site instead of stalling the run, `Retry-After` honoured (seconds or a date; above 30 s reported),
  the private-network guard on every request and redirect hop (resolve-and-check, then connect to the checked
  address; ports 80 and 443 only; IPv6 forms that wrap an address, 6to4 and site-local addresses refused), a time
  limit per attempt and one for the whole request (redirects, retries and robots.txt included), and decompression in
  small steps with a capped size. robots.txt rules are matched in linear time, so a hostile file can't stall a run;
  a robots.txt cut at the size cap loses its partial last line, and its retries honour `Retry-After`. A malformed
  address or redirect target is reported for that company instead of crashing the run.
- Company names: a guess that fails for robots.txt or network reasons (e.g. an unknown Personio name redirecting to
  Personio's site, whose robots.txt answered 429) just means "not on that platform", with no retries and no
  robots.txt message; an unknown name is answered in seconds.
- A careers domain that doesn't exist is reported as such, not as a robots.txt problem.
- Jobs reserved against the run's limit for a company whose job details robots.txt then disallows are given back to
  the other companies in the run.
- Companies as a Workday career-site URL (`myworkdayjobs.com`, including localized and single-job links, or
  `myworkdaysite.com/recruiting/…`) or a careers page that links to one. Company names, the `workday:` short form
  and boards on other platforms are refused with a message saying what to paste instead; the rest of the run continues.
- Exact posting date, description, employment type, workplace type and country from each job's detail record,
  fetched only for the jobs the run returns. Title keywords are sent to Workday's own search.
- Filters: title keywords, exclude keywords, locations, remote only, posted within N days, max jobs per company;
  "only jobs new since my last run", remembered per company and filter combination in the user's own
  `workday-jobs-seen` store.
- Charged per job returned ($2.00 per 1,000, plus $0.00005 per run start), through Apify's standard
  `apify-default-dataset-item` event.
- "Max jobs per run" input, and the maximum cost per run is honoured: once either is covered, companies still
  being fetched are cancelled and the rest are skipped (listed as `boardsSkipped` in `RUN_STATS`).
- Failure isolation: a failing company, a malformed job record or a failed detail request only affects itself.
- A run where no company is on Workday (or none can be found) ends successfully with 0 jobs and a status
  message saying so; `RUN_STATS` (`unresolved`) and the log say why for each company. A malformed company line
  (e.g. `http://[bad`) is reported for that line and never crashes the run.
- "Only jobs new since my last run" remembers a job only once it's in your dataset, so a run that stops early never
  hides jobs from the next one.
- `RUN_STATS` has the same keys on every exit path. No proxy input: Workday's public API needs none.
- Identifies itself honestly (User-Agent `HumbleEchidnaApify/1.0 (+https://apify.com/humble-echidna)`) and
  checks every host's robots.txt first, careers pages included: anything a site disallows is never requested and the
  company is reported with the reason; Crawl-delay is respected.
