Workday says the board has 2,000 jobs. Target has 12,525. Reading the rest.
Ask a Workday career site for its jobs and the first answer states a total: r = requests.post( "https://target.wd5.myworkdayjobs.com/wday/cxs/target/targetcareers/jobs", json={"appliedFacets": {}, "limit": 20,
Ask a Workday career site for its jobs and the first answer states a total:
r = requests.post(
"https://target.wd5.myworkdayjobs.com/wday/cxs/target/targetcareers/jobs",
json={"appliedFacets": {}, "limit": 20, "offset": 0, "searchText": ""},
)
r.json()["total"] # 2000
Target does not have 2,000 open jobs. It has 12,525. The number is the most
that search will return, and once you have paged to it the API just re-serves
page one: offsets past the ceiling come back as the first twenty postings
again, forever, which is how a paging loop that stops on "empty page" turns
into an infinite one.
Measured on 2026-09-22 across 3,916 Workday boards: 59 of them sit at exactly
that wall (a board shows 1,990-2,000 because postings of one requisition merge
into one job). Among them Target, Walmart, NVIDIA, Accenture, Citi, Airbus,
T-Mobile, PNC, Abbott, Kohl's, Sysco, Circle K and Trinity Health.
The counts are in the same answer you already have
The response carries a facets list, and those counts are of the whole board,
not of the 2,000:
Location_Country United States of America 12,452 India 73
Location_Region_State_Province California 1,701 Texas 879 Florida 803 ...
jobFamilyGroup Stores 12,023 Internships 132 ...
workerSubType Regular 11,538 Seasonal 854 Intern 133
timeType Variable 11,427 Full time 1,098
Four of those sum to exactly 12,525. That agreement is the useful part: a
facet a posting carries once sums to the board, a facet it can carry several
times (skills, locations) sums higher, and one only some postings carry sums
lower. So the board's real size is the sum the most facets agree on.
Each facet value is its own search, with its own ceiling
appliedFacets narrows the search, and the narrowed search gets a fresh
2,000:
body = {"appliedFacets": {"Location_Region_State_Province": ["<value id>"]},
"limit": 20, "offset": 0, "searchText": ""}
California is 1,701 postings, and 1,701 come back. So the board is read slice
by slice and the slices are joined on each posting's externalPath, which is
the posting's own address and therefore the one key that cannot collide:
- Read the first page. If
totalis exactly 2,000, take the facets. - Work out the real size (the sum the most facets agree on).
- Pick the facet that covers that size and whose every value is under the ceiling, fewest values first. Target: its 52 states.
- Where one value is still over the ceiling, apply it and split again by a second facet. Petco needs this: 2,980 of its jobs are "Retail (Stores)", and inside that slice the schedule splits it 1,893 / 1,024.
- Where no facet covers the slice at all, use the best partial one AND read the slice's own 2,000: Petco's schedule field is blank on 63 postings, and those come back in the plain read.
What it returns
Read whole, on 2026-09-22:
Target 12,499 of 12,536 655 requests
Michaels 5,071 of 5,071 279
Petco 3,774 of 3,798 298
Home Depot (Workday corporate site, 1,031, no ceiling)
Walmart went from 1,990 rows to 21,202, Circle K from 2,000 to 11,397.
Two things worth keeping when you build this:
A failed slice falls back to the plain 2,000. Target is ~650 requests
against ~100, so a transient error is six times likelier; a caller who got
2,000 rows yesterday should not get an exception today for the sake of the
other 10,499.
Nothing splits under the ceiling. If the caller wants 1,000 rows, the
plain search already answers, and the split is pure cost.
The other thing in that answer
While measuring this I found that bulletFields[0], which most code (mine
included) uses as the job id, is not an id on 224 of those boards: Thales
prints "Regular Employee" there, Michaels the state, Cracker Barrel the
store's street address. Anything that de-duplicates on it collapses the board:
61,107 jobs became 16,314, and a run for Thales returned 7 rows for 200 jobs.
The requisition is in the posting's address instead
(/job/<place>/<Title-Slug>_<req>), and the bullet is only safe when it IS
that requisition.
If you want the rows rather than the code, this is what
workday-jobs-scraper
does: a company name in, every open posting out, past the ceiling, as JSON.
Originally published by Dev.to WebDev. Aggregated on AIWithGhost for educational purposes — full credit and traffic to the original publisher.