All platforms

Phenom People Jobs API.

Talent experience platform with enterprise-scale career site and candidate journey tooling.

Phenom People
Live
120K+jobs indexed monthly
<3haverage discovery time
1hrefresh interval
Companies using Phenom People
GE AerospaceHelloFreshLarge global enterprises
Developer tools

Try the API.

Test Jobs, Feed, and Auto-Apply endpoints against https://connect.jobo.world with live request/response examples, then copy ready-to-use curl commands.

What's in every response.

Data fields, real-world applications, and the companies already running on Phenom People.

Data fields
  • Enterprise career sites
  • AI-assisted matching
  • Global hiring support
  • Candidate engagement tools
  • Workflow automation
  • Multi-language support
Use cases
  1. 01Enterprise job monitoring
  2. 02Global talent market analysis
  3. 03Multi-brand career site scraping
  4. 04Large-scale job aggregation
Trusted by
GE AerospaceHelloFreshLarge global enterprises
DIY GUIDE

How to scrape Phenom People.

Step-by-step guide to extracting jobs from Phenom People-powered career pages—endpoints, authentication, and working code.

Hybridintermediate~100-120 requests/minute (unofficial); some sites use Cloudflare protectionNo auth

Discover the company refNum

Each Phenom People site has a unique refNum code required for API requests. Extract it from the page HTML or by inspecting API responses from the careers site.

Step 1: Discover the company refNum
import requests
from bs4 import BeautifulSoup

def get_refnum(domain: str) -> str | None:
    url = f"https://{domain}/global/en/search-results"
    response = requests.get(url, timeout=10)
    soup = BeautifulSoup(response.text, "html.parser")

    # Look for refNum in script tags or data attributes
    for script in soup.find_all("script"):
        if script.string and "refNum" in script.string:
            # Extract refNum using string parsing
            import re
            match = re.search(r'"refNum":"([^"]+)"', script.string)
            if match:
                return match.group(1)
    return None

refnum = get_refnum("careers.geaerospace.com")
print(f"Found refNum: {refnum}")

Fetch job listings from the widgets API

Use the /widgets endpoint with ddoKey 'refineSearch' to retrieve paginated job listings. Each job includes a teaser description and metadata.

Step 2: Fetch job listings from the widgets API
import requests

def fetch_jobs(domain: str, refnum: str, page: int = 0, size: int = 20) -> dict:
    url = f"https://{domain}/widgets"
    payload = {
        "lang": "en_global",
        "deviceType": "desktop",
        "country": "global",
        "pageName": "search-results",
        "size": size,
        "from": page * size,
        "jobs": True,
        "counts": True,
        "all_fields": ["category", "country", "city", "type"],
        "clearAll": False,
        "jdsource": "facets",
        "isSliderEnable": False,
        "pageId": "page20",
        "siteType": "external",
        "keywords": "",
        "global": True,
        "selected_fields": {},
        "sort": {"order": "desc", "field": "postedDate"},
        "locationData": {},
        "refNum": refnum,
        "ddoKey": "refineSearch"
    }

    response = requests.post(
        url,
        json=payload,
        headers={"Content-Type": "application/json"},
        timeout=15
    )
    return response.json()

data = fetch_jobs("careers.geaerospace.com", "GAOGAYGLOBAL", page=0)
jobs = data.get("refineSearch", {}).get("data", {}).get("jobs", [])
total = data.get("refineSearch", {}).get("totalHits", 0)
print(f"Found {len(jobs)} jobs (total: {total})")

Parse job listings data

Extract relevant fields from each job object including title, location, category, and the jobSeqNo needed to construct detail page URLs.

Step 3: Parse job listings data
for job in jobs:
    parsed = {
        "job_id": job.get("jobId"),
        "req_id": job.get("reqId"),
        "title": job.get("title"),
        "location": job.get("location"),
        "category": job.get("category"),
        "type": job.get("type"),
        "posted_date": job.get("postedDate"),
        "apply_url": job.get("applyUrl"),
        "teaser": job.get("descriptionTeaser", "")[:200],
        "job_seq_no": job.get("jobSeqNo"),
        "is_multi_location": job.get("isMultiLocation", False),
    }
    print(f"{parsed['title']} - {parsed['location']}")

Fetch full job descriptions from HTML

The API only returns teaser descriptions. To get full job details, scrape the job detail page using the jobSeqNo to construct the URL.

Step 4: Fetch full job descriptions from HTML
import requests
from bs4 import BeautifulSoup
from urllib.parse import quote

def fetch_job_details(domain: str, job_seq_no: str, title: str) -> dict:
    title_slug = quote(title.lower().replace(" ", "-"))
    url = f"https://{domain}/global/en/job/{job_seq_no}/{title_slug}"

    response = requests.get(url, timeout=10)
    soup = BeautifulSoup(response.text, "html.parser")

    # Extract job details from HTML
    title_elem = soup.select_one("h1.job-title, h1")
    location_elem = soup.select_one(".job-location, [class*='location']")
    desc_elem = soup.select_one(".job-description, [class*='description']")
    apply_elem = soup.select_one("a[href*='apply']")

    return {
        "title": title_elem.get_text(strip=True) if title_elem else None,
        "location": location_elem.get_text(strip=True) if location_elem else None,
        "description": desc_elem.get_text(strip=True) if desc_elem else None,
        "apply_url": apply_elem.get("href") if apply_elem else None,
        "url": url,
    }

# Fetch details for first job
if jobs:
    first_job = jobs[0]
    details = fetch_job_details(
        "careers.geaerospace.com",
        first_job["jobSeqNo"],
        first_job["title"]
    )
    print(f"Full description length: {len(details.get('description', ''))}")

Handle pagination and rate limiting

Paginate through all jobs using the 'from' parameter and implement delays between requests to avoid rate limiting.

Step 5: Handle pagination and rate limiting
import time
import requests

def fetch_all_jobs(domain: str, refnum: str, delay: float = 0.5) -> list:
    all_jobs = []
    page = 0
    size = 20

    while True:
        data = fetch_jobs(domain, refnum, page=page, size=size)
        result = data.get("refineSearch", {})
        jobs = result.get("data", {}).get("jobs", [])
        total = result.get("totalHits", 0)

        if not jobs:
            break

        all_jobs.extend(jobs)
        print(f"Page {page}: fetched {len(jobs)} jobs (total: {len(all_jobs)}/{total})")

        if len(all_jobs) >= total:
            break

        page += 1
        time.sleep(delay)  # Rate limiting

    return all_jobs

all_jobs = fetch_all_jobs("careers.geaerospace.com", "GAOGAYGLOBAL")
print(f"Total jobs collected: {len(all_jobs)}")

Alternative: Discover jobs via sitemap

As an alternative to the API, use the sitemap index to discover all job URLs. Each sitemap contains up to 500 job URLs with last modified dates.

Step 6: Alternative: Discover jobs via sitemap
import requests
import xml.etree.ElementTree as ET

def discover_jobs_from_sitemap(domain: str) -> list:
    sitemap_url = f"https://{domain}/global/en/sitemap_index.xml"
    response = requests.get(sitemap_url, timeout=10)

    root = ET.fromstring(response.content)
    namespace = {"sm": "http://www.sitemaps.org/schemas/sitemap/0.9"}

    job_urls = []
    # Parse sitemap index for individual sitemaps
    for sitemap in root.findall(".//sm:loc", namespace):
        sitemap_response = requests.get(sitemap.text, timeout=10)
        sitemap_root = ET.fromstring(sitemap_response.content)

        # Extract job URLs from each sitemap
        for url in sitemap_root.findall(".//sm:loc", namespace):
            if "/job/" in url.text:
                job_urls.append(url.text)

    return job_urls

job_urls = discover_jobs_from_sitemap("careers.geaerospace.com")
print(f"Discovered {len(job_urls)} job URLs from sitemaps")
Common issues
criticalMissing or incorrect refNum causes empty results

The refNum is company-specific and must be extracted from the page HTML or API responses. Check script tags and data attributes on the search page.

highCSRF token required for some company configurations

Make an initial GET request to extract the CSRF token from cookies or meta tags, then include it in the x-csrf-token header for POST requests.

highAPI only returns descriptionTeaser, not full descriptions

Use a hybrid approach: fetch job IDs from the API, then scrape full descriptions from individual job detail HTML pages.

mediumCloudflare protection blocks automated requests

Implement proper request headers, session cookies, and delays. Some sites may require browser automation for initial access.

lowDifferent locale/language configurations per site

Check the lang parameter in API requests and adjust for company-specific locales (e.g., en_global, en_us, fr_fr).

lowSitemap not available or returns 404

Not all Phenom sites expose sitemaps at the standard path. Fall back to the widgets API approach if sitemap discovery fails.

mediumJob detail page returns 404 or redirects

The jobSeqNo format may vary between companies. Try using just the jobId instead, or check if the job has been removed from the listings.

Best practices
  1. 1Extract refNum dynamically from each company's page rather than hardcoding
  2. 2Use the hybrid API + HTML approach for complete job data
  3. 3Implement pagination with the 'from' parameter to retrieve all jobs
  4. 4Add delays between requests to avoid rate limiting and bot detection
  5. 5Cache results as job boards typically update daily
  6. 6Handle multi-location jobs by checking isMultiLocation and multi_location fields
  7. 7Try sitemap discovery as a fallback if the widgets API is blocked
Or skip the complexity

One endpoint. All Phenom People jobs. No scraping, no sessions, no maintenance.

Get API access
cURL
curl "https://enterprise.jobo.world/api/jobs?sources=phenom people" \
  -H "X-Api-Key: YOUR_KEY"
Ready to integrate

Access Phenom People
job data today.

One API call. Structured data. No scraping infrastructure to build or maintain — start with the free tier and scale as you grow.

99.9%API uptime
<200msAvg response
50M+Jobs processed