DEV Community

Daniel Meshulam
Daniel Meshulam

Posted on Fully Autonomous

Oracle Recruiting Cloud jobs API: Marriott, Kroger and JPMorgan careers sites as JSON

A lot of large employers run their careers page on Oracle Recruiting Cloud (Fusion HCM "Candidate Experience"): Marriott, Kroger, JPMorgan Chase, Hilton, AutoZone, Dollar General. The page looks custom, but every one of them loads its jobs from the same public REST endpoint, with no key and no login.

1. Read the host and the site from the careers URL

https://ejwl.fa.us2.oraclecloud.com/hcmUI/CandidateExperience/en/sites/CX
        └──────── host ─────────┘                                └ site ┘
Enter fullscreen mode Exit fullscreen mode

That is Marriott's. The host label (ejwl) and the site code say nothing about the employer, so you cannot derive them from a company name or domain; you need the real URL.

2. List the host's sites

One host often serves several sites. Ask it:

curl -s "https://ejwl.fa.us2.oraclecloud.com/hcmRestApi/resources/latest/recruitingCESites?onlyData=true&limit=200" \
  | jq -r '.items[] | "\(.SiteNumber)  \(.SiteName)"'
Enter fullscreen mode Exit fullscreen mode

Marriott has four: CX (Careers at Marriott), CX_1 (US and Canada campus), CX_1001 (non-US campus) and CX_1004 (an acquisition site).

3. Read the jobs, with expand

curl -s "https://ejwl.fa.us2.oraclecloud.com/hcmRestApi/resources/latest/recruitingCEJobRequisitions?onlyData=true&expand=requisitionList.secondaryLocations&finder=findReqs;siteNumber=CX,limit=200,offset=0,sortBy=POSTING_DATES_DESC" \
  | jq '.items[0].TotalJobsCount, (.items[0].requisitionList | length)'
Enter fullscreen mode Exit fullscreen mode

Three things will return the wrong answer without an error.

Leave out expand=requisitionList... and you get the count and no rows. The response still says how many jobs there are; the list of them is a child collection that only comes back when you ask for it.

An unknown siteNumber is not an error. Oracle answers 200 with some default site's jobs. A typo returns somebody's postings, just not the ones you asked for, so check the code against step 2 before you trust it.

One query stops at 10,000 records. Pages of 200 work up to offset 9,800; offset 9,990 returned nothing. Marriott had 13,423 open jobs that day, so a straight walk loses a quarter of them. Split the site instead: add facetsList=CATEGORIES to the finder and the first response lists every job category with its count. Marriott's 26 categories summed exactly to its 13,423 jobs, so reading category by category gets all of them.

4. The description is one more call per job

List rows carry the title, posting date, country, workplace type, job family and schedule, but no description. That is a detail call by id:

curl -s "https://ejwl.fa.us2.oraclecloud.com/hcmRestApi/resources/latest/recruitingCEJobRequisitionDetails?expand=all&onlyData=true&finder=ById;Id=%22<Id>%22,siteNumber=CX" \
  | jq -r '.items[0].ExternalDescriptionStr' | head -c 400
Enter fullscreen mode Exit fullscreen mode

It returns the external description, responsibilities and qualifications as HTML strings.

Hosted

I keep a map of 1,067 employers on Oracle Recruiting Cloud, 1,808 career sites, each one read for real postings before it went in, so you can ask by name: "Marriott", "Kroger", "JPMorgan Chase". That is Oracle Recruiting Jobs Scraper on Apify, with the category split and the site checks above built in. For a company on any other careers system, Company Career Page Jobs Scraper takes a name or domain. The public endpoints of 16 other systems, each with a tested curl, are in job-board-apis.

Top comments (0)