RTX (careers.rtx.com), UPS ( www.jobs-ups.com) and CVS Health ( jobs.cvshealth.com) run their careers sites on Phenom. Each site's own search is one POST to /widgets, with no key and no login, and robots.txt leaves it alone: it disallows */apply, */jobcart, */chatbot and */px-widgets, not /widgets.
curl -s -X POST "https://careers.rtx.com/widgets" -H "Content-Type: application/json" \
-d '{"ddoKey":"refineSearch","jobs":true,"from":0,"size":500,"sort":{"order":"desc","field":"dateCreated"}}' \
| jq '.refineSearch.totalHits, (.refineSearch.data.jobs | length)'
That printed 4834 and 500. Five things to know, measured on 2026-10-27 with a few seconds between requests.
Leave out "jobs": true and the answer still carries totalHits, 4,834, with no jobs in it. size goes to 500: all 49 Phenom sites we read gave 500 rows for size: 500 (or their whole list), and CVS gave 500 for size: 1000. Asking for 100 a page is five times the requests.
dateCreated, not postedDate
postedDate is a day at midnight, so hundreds of jobs share each value, and the order among them changes from one request to the next. Paging RTX's jobs (4,809 that evening) 100 at a time by postedDate, a new connection per request, gave 4,667 distinct jobs in one read and 4,719 in the next: the missing ones were on no page, and others came twice. Panera, read 500 at a time, lost 172 of 6,291. dateCreated carries the time to the millisecond:
for from in $(seq 0 500 4500); do
curl -s -X POST "https://careers.rtx.com/widgets" -H "Content-Type: application/json" \
-d "{\"ddoKey\":\"refineSearch\",\"jobs\":true,\"from\":$from,\"size\":500,\"sort\":{\"order\":\"desc\",\"field\":\"dateCreated\"}}" \
| jq -r '.refineSearch.data.jobs[].jobSeqNo'
sleep 3
done | sort -u | wc -l
That printed 4834, all of them. A field the site does not sort on, such as jobSeqNo, answers totalHits 0 and no error.
CVS Health lists 19,664 jobs. A page answers only while from plus size stays under 10,000:
curl -s -X POST "https://jobs.cvshealth.com/widgets" -H "Content-Type: application/json" \
-d '{"ddoKey":"refineSearch","jobs":true,"from":9900,"size":100,"sort":{"order":"desc","field":"dateCreated"}}' \
| jq '.refineSearch.totalHits, (.refineSearch.data.jobs | length)'
That prints 0 and 0, with HTTP 200: the same answer as the end of the list. from 9,899 with size 100 still answers. A loop that pages until an empty page stops at 9,900 and reports success. Ours did, until this week: it had stored O'Reilly Auto (19,062 jobs) and Dollar Tree (15,519) at exactly 9,900 each.
counts: true with the fields you name returns each facet's values and their counts, and selected_fields narrows the search to one value:
curl -s -X POST "https://jobs.cvshealth.com/widgets" -H "Content-Type: application/json" \
-d '{"ddoKey":"refineSearch","jobs":true,"from":0,"size":1,"counts":true,"all_fields":["category"]}' \
| jq '.refineSearch.data.aggregations[] | select(.field=="category") | .value'
CVS's nine categories add up to its total exactly, the largest (Pharmacy) at 7,572, so each pages under the window. O'Reilly files 18,609 of its 19,062 under "Stores", so it goes by state: 49 values, the largest 2,345. Skip city: the facet lists at most 1,000 values, which added up to 6,795 of CVS's jobs. A job in two states is in two slices, so dedupe on jobSeqNo.
The Apply link names the system underneath. RTX's 500 newest all apply through Workday (globalhr.wd5), CVS's through Workday ( cvshealth.wd1), Eli Lilly's through Workday ( lilly.wd115). UPS splits: of its 500 newest, 252 apply through Fountain and 248 through Workday. So the same jobs can often be read from Workday too, with a different count: CVS's Workday site said 19,706 the hour Phenom said 19,665. Read one source per employer, or dedupe on the requisition number, reqId, which is the number in the Workday address.
Company Career Page Jobs Scraper on Apify takes RTX or UPS by name, or any Phenom careers site as phenom:jobs.cvshealth.com, reads 500 a page by dateCreated, and slices a site past 10,000 by its facets: O'Reilly Auto came back whole, 19,062 jobs. Every other system's public endpoint, with a tested curl, is in job-board-apis.