Workday is the careers backend for a large share of big employers: banks, retailers, hospitals, chipmakers. Their job pages live on *.myworkdayjobs.com, and there is no single public search across them. This post shows:
- How a single Workday careers site works under the hood (the JSON endpoint behind it).
- A 25-line Python script that pulls every job from one company.
- What changes when you need all Workday companies, and a ready-made API for that.
1. The endpoint behind every Workday careers page
Open any Workday careers site, for example
https://nvidia.wd5.myworkdayjobs.com/en-US/NVIDIAExternalCareerSite, and watch the network tab. The page calls:
POST https://nvidia.wd5.myworkdayjobs.com/wday/cxs/nvidia/NVIDIAExternalCareerSite/jobs Content-Type: application/json {"appliedFacets": {}, "limit": 20, "offset": 0, "searchText": ""} The URL pattern is https://{tenant}.{wdN}.myworkdayjobs.com/wday/cxs/{tenant}/{site}/jobs. The response has total and a jobPostings list (title, externalPath, locationsText, postedOn like "Posted 3 Days Ago"). The full description is a second GET on /wday/cxs/{tenant}/{site}{externalPath}.
2. One company in Python
import requests TENANT, WD, SITE = "nvidia", "wd5", "NVIDIAExternalCareerSite" BASE = f"https://{TENANT}.{WD}.myworkdayjobs.com/wday/cxs/{TENANT}/{SITE}" jobs, offset = [], 0 while True: r = requests.post(f"{BASE}/jobs", json={"appliedFacets": {}, "limit": 20, "offset": offset, "searchText": ""}, timeout=30) r.raise_for_status() page = r.json().get("jobPostings", []) if not page: break jobs += page offset += 20 print(len(jobs), "jobs") for j in jobs[:10]: print(j["title"], "|", j.get("locationsText"), "|", j.get("postedOn")) Things that bite you in practice:
- Finding the tenant, wdN and site name. Company names don't map to them. "Bank of America" is not
bankofamerica.wd1, and many companies run several sites. - Relative dates. "Posted 30+ Days Ago" is all you get from the list. You need to store first-seen dates yourself.
- Closed jobs just disappear, so you need state between runs to know what closed.
- Big boards report
total: 2000. NVIDIA's board returned exactly 2000 when I checked on Oct 22, 2026, which looks like a cap. To get everything, split the search by the location or job-family facets inappliedFacets. Go easy on request rate too. - Salary is only in the description text, in many formats.
For one or five companies, the script above is all you need. Run it daily and diff the IDs.
3. All Workday companies at once
If you need "every data engineer job posted on any Workday site in the last 24 hours", crawling 2,000+ tenants yourself becomes a data-engineering project. I maintain an index that does this daily and exposes it as an API on Apify: Workday Jobs Scraper (730K+ jobs from 2,100+ Workday sites at the time of writing). Disclosure: I built it.
Search by title and location across all of them:
curl -s -X POST \ "https://api.apify.com/v2/acts/cleanrowdata~workday-jobs-scraper/run-sync-get-dataset-items?format=csv" \ -H "Authorization: Bearer $APIFY_TOKEN" -H "Content-Type: application/json" \ -d '{"timeRange":"24h","titleSearch":["data engineer","analytics engineer"],"locationSearch":["United States","Canada"],"limit":500}' \ -o workday_jobs.csv Or every open job at named companies, by real name (no tenant hunting):
{"timeRange":"all","companies":["Bank of America","Salesforce","https://nvidia.wd5.myworkdayjobs.com/en-US/NVIDIAExternalCareerSite"],"limit":1000} Other inputs that are handy:
-
{"timeRange":"7d","remoteOnly":true,"hasSalary":true,"limit":200}: remote Workday jobs that list a salary -
{"timeRange":"7d","titleSearch":["engineer"],"seniority":["senior","staff_principal"],"minSalaryUsd":150000,"onlyNewSinceLastRun":true,"limit":500}: a daily feed of only new senior roles over $150K -
{"timeRange":"7d","jobStatus":"closed","companies":["Bank of America","Salesforce"],"limit":1000}: jobs that closed this week (useful for time-to-fill analysis)
Every row has the same columns: title, company, location, country, remote, workplace_type, employment_type, posted_at, first_seen, last_seen, status, closed_at, salary_min/max/currency/period, job_url, apply_url, description.
Pricing is per job returned: $2.50 per 1,000 on Apify's free plan, and the free monthly credit covers a first test easily.
More examples (Python, Node, n8n): github.com/cleanrowdata/jobs-api-examples
Which one should you use?
| Need | Use |
|---|---|
| A few known companies, you're fine maintaining a script | The Python above, run daily |
| Thousands of companies, search by title/location/salary, closed-job tracking | An index/API like the one above |
| Greenhouse/Lever/Ashby too | The same approach. Their APIs are public JSON (boards-api.greenhouse.io, api.lever.co/v0/postings, api.ashbyhq.com/posting-api/job-board) |
Questions or a Workday site that doesn't parse? Drop it in the comments.
