Oracle Recruiting Jobs API: Get Oracle Cloud HCM Jobs as JSON

CleanJobData Engineering

TL;DR

Oracle Recruiting Cloud (part of Oracle Fusion Cloud HCM) career sites load jobs from a keyless REST resource, recruitingCEJobRequisitions, with paging set inside the finder parameter. You need the tenant host and the career site number, and a wrong site number returns a different job set instead of an error. The list has titles, dates and locations but no description, so each job needs a recruitingCEJobRequisitionDetails call. There's no salary field, and the remote flag is only filled on some postings.

On this page

To get a company's jobs from Oracle Recruiting Cloud, call https://{host}/hcmRestApi/resources/latest/recruitingCEJobRequisitions?onlyData=true&finder=findReqs;siteNumber={site},limit=100,offset=0 with no API key. The list returns titles, dates and locations, and each job's full description comes from one recruitingCEJobRequisitionDetails request.

That's the DIY route, and it works for a handful of companies you already know. If you'd rather not build and maintain an Oracle Recruiting scraper, CleanJobData already ingests ATS platforms and company career sites and serves the jobs normalized through one REST API — see the Jobs API docs.

At a Glance

EndpointGET https://{host}/hcmRestApi/resources/latest/recruitingCEJobRequisitions?onlyData=true&finder=findReqs;siteNumber={site},limit=100,offset=0
Detail endpointGET https://{host}/hcmRestApi/resources/latest/recruitingCEJobRequisitionDetails?expand=all&onlyData=true&finder=ById;Id={id},siteNumber={site}
API keyNone
Paginationlimit and offset inside finder, 100 per page
Full descriptionDetail call, split across three HTML fields
Salary fieldNo
RemoteWorkplaceType, filled on some postings only

Finding the Host and Site Number

Oracle's candidate-facing career sites have URLs like:

https://acme.fa.us2.oraclecloud.com/hcmUI/CandidateExperience/en/sites/CX_1/

You need two values from that URL:

  • Host. acme.fa.us2.oraclecloud.com. The fa.us2 part is a shared Oracle Cloud pod, and other regions such as fa.us6 and fa.ca2 exist too.
  • Site number. The segment after /sites/, here CX_1. Sites are named CX, CX_1, CX_2, CX_1001 and so on, and some have names like jobsearch.

Copy the site number exactly. A wrong one doesn't fail: on one tenant, the real site listed 86 jobs while a made-up site number returned 200 with 150 jobs drawn from the tenant's other career sites. If a company embeds the career site on its own domain, open the Network tab and look for requests to hcmRestApi.

The List Request

curl "https://acme.fa.us2.oraclecloud.com/hcmRestApi/resources/latest/recruitingCEJobRequisitions?onlyData=true&expand=requisitionList.secondaryLocations&finder=findReqs;siteNumber=CX_1,limit=100,offset=0,sortBy=POSTING_DATES_DESC"

The paging parameters go inside finder, separated by commas. expand=requisitionList.secondaryLocations adds a job's extra locations, and sortBy=POSTING_DATES_DESC puts the newest jobs first.

The response is a search envelope: items[0] holds the search settings and the total, and the jobs sit in items[0].requisitionList.

{
  "items": [
    {
      "SiteNumber": "CX_1",
      "TotalJobsCount": 842,
      "requisitionList": [
        {
          "Id": "753717",
          "Title": "Store Associate",
          "PostedDate": "2026-11-01",
          "PrimaryLocation": "Bristol, VT, United States",
          "PrimaryLocationCountry": "US",
          "ShortDescriptionStr": "7 MAIN ST 05443 BRISTOL,VT UNITED STATES",
          "WorkplaceType": "",
          "JobSchedule": null,
          "secondaryLocations": []
        }
      ]
    }
  ],
  "count": 1,
  "hasMore": false
}
FieldWhat it is
IdRequisition ID, the same value in the list and the detail call. Not always numeric
TitleJob title
PostedDatePosting date, date only
PrimaryLocationComma-separated location text
PrimaryLocationCountryISO alpha-2 country code
secondaryLocationsExtra locations with Name, CountryCode, Latitude, Longitude (needs expand)
ShortDescriptionStrShort text set by the tenant, not the description. On one tenant it was the street address
WorkplaceTypeFor example "Hybrid", often an empty string
JobScheduleFor example "Full time" or "Part time", when set
TotalJobsCountOn items[0], the total for this site

The outer count and hasMore describe the envelope, not the jobs: a site with thousands of jobs still reports "count": 1 and "hasMore": false. Use TotalJobsCount instead.

Pagination

Increase offset inside the finder by the number of rows you actually received, and stop on an empty requisitionList or when offset reaches TotalJobsCount. A page size of 100 works well.

Dedupe by Id. Offset paging over a date sort isn't stable: a job posted while you're paging shifts the window, and the same Id can show up on two pages.

The Detail Request

curl "https://acme.fa.us2.oraclecloud.com/hcmRestApi/resources/latest/recruitingCEJobRequisitionDetails?expand=all&onlyData=true&finder=ById;Id=753717,siteNumber=CX_1"

The job is items[0]. Fields worth knowing:

  • ExternalDescriptionStr, ExternalResponsibilitiesStr, ExternalQualificationsStr. The posting body, as HTML. Join whichever are non-empty, in that order. The last two are often empty strings.
  • CorporateDescriptionStr, OrganizationDescriptionStr. Company boilerplate that repeats on every job for the tenant. Leave them out unless you want it.
  • ExternalPostedStartDate. A full ISO timestamp such as 2026-11-01T11:31:07+00:00. Prefer it over the list's date-only PostedDate.
  • ExternalPostedEndDate. The scheduled end of the posting. Treat it as a hint and detect closed jobs by comparing lists.
  • JobSchedule, JobLevel, Category, JobFunction. Classification fields, filled per tenant.
  • primaryLocationCoordinates. Latitude and longitude for PrimaryLocation, as strings.
  • workLocation. A facility record. It can name a different place from the advertised location, so don't use it as the job's location.
  • requisitionFlexFields. Tenant-specific Prompt / Value pairs.

The API has no apply link. The candidate-facing job page is:

https://{host}/hcmUI/CandidateExperience/en/sites/{site}/job/{Id}

Fetching Jobs (Python)

import requests
 
def list_oracle_jobs(host: str, site: str) -> list[dict]:
    base = f"https://{host}/hcmRestApi/resources/latest"
    seen, jobs, offset = set(), [], 0
    while True:
        finder = f"findReqs;siteNumber={site},limit=100,offset={offset},sortBy=POSTING_DATES_DESC"
        resp = requests.get(
            f"{base}/recruitingCEJobRequisitions",
            params={"onlyData": "true", "expand": "requisitionList.secondaryLocations", "finder": finder},
            timeout=25,
        )
        resp.raise_for_status()
        envelope = (resp.json().get("items") or [{}])[0]
        rows = envelope.get("requisitionList") or []
        total = envelope.get("TotalJobsCount") or 0
        if not rows:
            break
        for row in rows:
            job_id = str(row["Id"])
            if job_id not in seen:
                seen.add(job_id)
                jobs.append(row)
        offset += len(rows)
        if total and offset >= total:
            break
    return jobs
 
def get_oracle_detail(host: str, site: str, job_id: str) -> dict | None:
    resp = requests.get(
        f"https://{host}/hcmRestApi/resources/latest/recruitingCEJobRequisitionDetails",
        params={"expand": "all", "onlyData": "true", "finder": f"ById;Id={job_id},siteNumber={site}"},
        timeout=20,
    )
    resp.raise_for_status()
    items = resp.json().get("items") or []
    if not items:
        return None  # the requisition is gone
    d = items[0]
    parts = [d.get(k) for k in ("ExternalDescriptionStr", "ExternalResponsibilitiesStr", "ExternalQualificationsStr")]
    return {
        "id": job_id,
        "title": d.get("Title"),
        "description_html": "\n".join(p for p in parts if p and p.strip()),
        "published": d.get("ExternalPostedStartDate"),
        "location": d.get("PrimaryLocation"),
        "country": d.get("PrimaryLocationCountry"),
        "workplace_type": d.get("WorkplaceType") or None,
        "url": f"https://{host}/hcmUI/CandidateExperience/en/sites/{site}/job/{job_id}",
    }

requests URL-encodes the finder value, and Oracle accepts it either way.

Gotchas

PrimaryLocation comes in three shapes. "Abilene, TX, United States" is city, region and country. "United States" is a country alone. Two parts are ambiguous: "TX, United States" is a region, but "Suva, Fiji" is a city. Take the country from PrimaryLocationCountry and check the first segment against a gazetteer before you call it a city. See the location normalization guide.

Coordinates change type. Latitude and Longitude are numbers in the list and strings in the detail response, so convert them before comparing.

IDs aren't always numbers. Some tenants use IDs like W734354. Store Id as a string.

Gone jobs return 200. A closed requisition's detail call answers 200 with an empty items array, not a 404.

One tenant can expose the same jobs on several sites. Some hosts publish the same requisitions under more than one site number. Opening a job page under a duplicate site answers with a 302 redirect to the main site, but the listing page doesn't redirect, so check a few job pages. Other sites mix shared jobs with jobs of their own. Dedupe by host plus Id.

WorkplaceType is patchy. It's set to values like "Hybrid" on some postings and empty on others from the same tenant, so also check the title and location for "remote" or "hybrid".

No employer name or salary. The payloads don't include the company name or any pay field, so you supply the name yourself and look for pay in the description text.

Candidate Experience API vs Oracle's Authenticated REST API

These resources sit inside Oracle's HCM REST API. Most of that API needs an authenticated user from the employer's Oracle Cloud instance and covers internal HR and recruiting data. The candidate-experience resources used here answer anonymous requests because the public career site depends on them, and they only return published jobs. If you want postings from companies you don't work with, these are the ones you can use.

When This Is Enough

For one employer whose host and site number you know, the list call plus one detail call per new job is straightforward, and large tenants page cleanly at 100 rows.

When It Isn't

Across many Oracle tenants you'll deal with duplicate sites, ambiguous locations and per-tenant field use, alongside other platforms like Workday and SmartRecruiters. See which ATS have a public job postings API for how they compare.

CleanJobData reads Oracle Recruiting sites alongside other platforms and returns one schema, with locations resolved to cities, states and countries and a remote type. There's no salary in Oracle's data, so that field can be empty. Try it in the Playground or see the API Documentation.

Skip the scraper: get this data from the CleanJobData API

If you'd rather not maintain an Oracle Recruiting collector, you can query normalized jobs from ATS platforms and company career sites with a single request. The response has structured city/state/country locations, parsed salary when the employer publishes one, a remote type, and company metadata, and you page through results with the cursor in pagination.next_page.

curl "https://api.cleanjobdata.com/jobs?title=engineer&domain=acme.fa.us2.oraclecloud.com&limit=20" \
  -H "Authorization: Bearer $CLEANJOBDATA_API_KEY"

The domain filter is an exact match on the host of each job's application_url. Oracle hosts belong to one tenant, so this scopes the query to that company; company_website_url and employer_id work too. Coverage depends on which employers are in the dataset, so check that the companies you care about appear before you rely on it.

FAQ

Does Oracle Recruiting Cloud have a public jobs API?

Yes. Career sites built on Oracle Recruiting load jobs from https://{host}/hcmRestApi/resources/latest/recruitingCEJobRequisitions, which needs no API key. You pass the career site number and paging values inside the finder parameter.

How do I find the Oracle site number?

It's the segment after /sites/ in the career site URL, for example CX_1 in /hcmUI/CandidateExperience/en/sites/CX_1/. Copy it exactly, because a wrong site number returns a different set of jobs instead of an error.

How do I get the full job description from Oracle?

Call recruitingCEJobRequisitionDetails with finder=ById;Id={id},siteNumber={site}. Join ExternalDescriptionStr, ExternalResponsibilitiesStr and ExternalQualificationsStr, skipping the empty ones.

Does the Oracle Recruiting API include salary?

No field we read carries pay. If an employer publishes a range, it's in the description HTML.