# Changelog of Greenhouse, Lever, Ashby & Workday Jobs: Careers Page Scraper (`yourevenings/careers-jobs-api`) Actor

- **URL**: https://apify.com/yourevenings/careers-jobs-api/changelog.md
- **Full Actor documentation**: https://apify.com/yourevenings/careers-jobs-api.md

## Changelog

### 0.1.14 (23 Oct 2026)

- Monitor mode only replaces a board's saved job list after a complete read:
  - Read failed: free `fetch_failed` row, saved list unchanged, no removed rows (before: a generic `error` row; the saved list was already left unchanged).
  - Partial read (Workday or Teamtailor cut short by the time limit, Workday jobs its search can't reach, SmartRecruiters paging stopping early): new jobs in the part read are returned; no removed rows; unseen saved jobs are kept; status `partial`. The no-change check is not charged on a partial read. Before, a partial read was saved as the whole board, giving false `removed` rows and then false `new` rows on the next run.
  - A board that suddenly reads 0 jobs after having some: free `empty_unconfirmed` row, saved list kept (with a pending flag); removals are only reported if the next run also reads 0.
- The same rules apply to the saved list when `persistState` is on outside monitor mode.
- Teamtailor now passes its "feed not fully read" flag through; SmartRecruiters reports when a full read stopped short of the board's total.
- Tests: `test/monitor-unit.mjs` (mocked board, no network).

### 0.1.13 (22 Oct 2026)

- New ATS: Teamtailor, read from the career site's public RSS job feed (`{career site}/jobs.rss`, documented by Teamtailor), paged 100 at a time. Input as a name, a domain, a `*.teamtailor.com` link, `teamtailor:{token}` or `teamtailor:{career-site host}` for sites on the employer's own domain. Also found from a company's careers page when it is a Teamtailor-built site, and included in moved-board lookups. Each career site's robots.txt is respected; one request at a time per site with a short gap.
- Teamtailor rows: department, team (division), locations (city, country), workplace type from remote status, publication date (`postedAtBasis: "teamtailor-published"`), job-page URL, description on request. The feed has no salary, employment type, update date or separate apply link.
- Company-name check ignores trailing Nordic legal forms (AB, AS, ASA, A/S, ApS, Oy, Oyj, publ) when confirming a guessed board.

### 0.1.12 (22 Oct 2026)

- Moved-board detection: when an explicit token or board URL answers "not found" (or the board lists no open jobs), the same token is tried on the other supported public feeds (Greenhouse, Lever US/EU, Ashby, Workable, SmartRecruiters, Recruitee, Personio). If found with open jobs, jobs are read from there and the company gets a free `board_moved` row with `fromAts`, `toAts` and `fromBoardToken`; job rows show `detectionMethod: "moved-board"`. Same company-name checks as for guesses; the smaller ATSs need a matching company name. Workday is not searched as a destination (no host is known from a token). Not found anywhere: free `not_found` as before, with the boards checked in the note.
- `COMPANY-STATUS` gains `fromAts` and `toAts` columns (at the end); the Detection view shows them.

### 0.1.11 (22 Oct 2026)

- New ATS: Personio, read from the employer's public XML job feed (`{token}.jobs.personio.de/xml`, or `.com`). Input as a name, a domain, a Personio career-page URL or `personio:{token}`. Only works when the employer has switched the public feed on; career pages with the feed off return a free `feed_disabled` row (explicit/URL/website-linked inputs) or a free `not_found` row with a note (guesses).
- Personio rows: department, team (recruiting category), main and additional offices, employment type from type and schedule, salary when in the feed, public job-page URL, `postedAt` = creation date in Personio (`postedAtBasis: "personio-created-at"`). Language-aware filters, monitor mode, duplicates, the cost limit and `COMPANY-STATUS` work as for the other ATS.
- Requests to Personio go one at a time with a short gap; each career site's robots.txt is respected.
- Name guesses also try the hyphenated form (`kbw-koeln`), still subject to the company-name check.
- README: "Works with" now lists Personio; short section on AI agents paying for runs via x402 or MPP (Apify agentic payments).

### 0.1.10 (22 Oct 2026)

- Language-aware filters, for every ATS (applied before charging, as before):
  - Title, exclude, location and department filters ignore accents (`developpeur` = "Développeur", `Zurich` = "Zürich"; ß, æ, ø, œ, ł handled).
  - Title and exclude keywords: a single word of 5+ letters also matches at the end of a compound word and with German -in/-innen endings (`entwickler` matches "Softwareentwickler", "Entwicklerin"). Still no prefix match (`java` ≠ "JavaScript") and no translation.
  - About 50 place-name groups matched together (Munich/München/Muenchen, Cologne/Köln, Zurich/Zürich, Vienna/Wien, NYC/New York, UK/United Kingdom, Germany/Deutschland, Bangalore/Bengaluru, ...), replacing the earlier short country list. Place names stay whole words.
  - More local remote words (ortsunabhängig, von zu Hause, à distance, a distancia, teletrabalho, op afstand, zdalnie, på distans, fjernarbejde, etätyö, na dálku, WFH, telework). They now also set `isRemote` when they appear in a job's location text (not its title). Workplace text that says both remote and hybrid is now `hybrid`.
- Fixed: double full stop in the status message when a run stops at the maximum charge ("maximum charge reached.. Per-company").
- README: Works-with block.
- Tests: `node test/language-test.mjs` (14/14), `python3 test/language-acceptance.py` (4/4, real boards).

### 0.1.9 (22 Oct 2026)

- Workday support: career sites on `*.myworkdayjobs.com` and `*.myworkdaysite.com`, resolved from a company name, a domain (careers-page links or the tenant's public robots.txt), a Workday URL or `workday:tenant.wdN/site`. Jobs come from the career site's own public job search (`/wday/cxs/{tenant}/{site}/jobs`), one request at a time per site with a gap, backoff on HTTP 429, robots.txt respected.
- Boards above Workday's 2,000-results-per-search limit are split by job family and other facets and merged by job ID; `companyTotalJobs` is the true total from Workday's facet counts. Anything not read (or a run about to time out) is explained in the company note and `COMPANY-STATUS`.
- Workday works with filters (before charging), `maxJobsPerCompany`, the budget stop, duplicates and monitor mode like the other ATSs. Job pages are read only where a filter needs them (all locations, dates older than 30 days) or for `includeDescription`.
- Fixed: `workplaceType` labelled "Homeoffice", "Home Office" and "Home-Office" as onsite. These, "mobiles Arbeiten" and common equivalents (télétravail, teletrabajo, remoto, thuiswerk, telelavoro, smart working) now count as remote; hybrid wording (hybrid, hybride, híbrido) stays hybrid. Test: `node test/workplace-test.mjs`.
- New job-row field `postedAtBasis` (`board-date` or `approximate-from-listing-text`).
- Status message: counts companies and COMPANY-STATUS lines separately, singular wording ("1 company", "1 line"), and "jobs not returned" instead of "matching jobs" when no filters are set.

### 0.1.8 (22 Oct 2026)

- Completeness proof: `companyTotalJobs` (the board's open-job count before filters and limits) on every job row, and on company rows for boards that were read. For SmartRecruiters it uses the board's `totalFound`.
- New `COMPANY-STATUS` CSV in the default key-value store: one line per input (input, company, ats, boardToken, status, totalJobs, returned, filteredOut, note), including exact repeats (`duplicate`) and companies not reached (`skipped_budget`). Linked from the final status message and the Output tab.
- No fields renamed; status rows stay free.

### 0.1.7 (22 Oct 2026)

- Added job filters applied before charging: `titleKeywords`, `excludeTitleKeywords`, `locations`, `remoteOnly`, `departments`, `postedWithinDays`, `keepJobsWithoutPostedDate`. Filtered-out jobs are never pushed or charged; in monitor mode filters apply to new and removed jobs.
- New fields (no renames): `postedAtUnknown` on job rows; `companyTotalJobs`, `filteredOut`, `jobsReturned` on company rows when filters are set; new company status `no_matching_jobs`; `filters` and `filteredOut` in `SUMMARY`.

### 0.1.6 (22 Oct 2026)

- README: "Why this one" list; listing text synced with the Store.
