Phenom People Jobs API.
Talent experience platform with enterprise-scale career site and candidate journey tooling.
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.
- Enterprise career sites
- AI-assisted matching
- Global hiring support
- Candidate engagement tools
- Workflow automation
- Multi-language support
- 01Enterprise job monitoring
- 02Global talent market analysis
- 03Multi-brand career site scraping
- 04Large-scale job aggregation
How to scrape Phenom People.
Step-by-step guide to extracting jobs from Phenom People-powered career pages—endpoints, authentication, and working code.
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}")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})")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']}")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', ''))}")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)}")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")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.
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.
Use a hybrid approach: fetch job IDs from the API, then scrape full descriptions from individual job detail HTML pages.
Implement proper request headers, session cookies, and delays. Some sites may require browser automation for initial access.
Check the lang parameter in API requests and adjust for company-specific locales (e.g., en_global, en_us, fr_fr).
Not all Phenom sites expose sitemaps at the standard path. Fall back to the widgets API approach if sitemap discovery fails.
The jobSeqNo format may vary between companies. Try using just the jobId instead, or check if the job has been removed from the listings.
- 1Extract refNum dynamically from each company's page rather than hardcoding
- 2Use the hybrid API + HTML approach for complete job data
- 3Implement pagination with the 'from' parameter to retrieve all jobs
- 4Add delays between requests to avoid rate limiting and bot detection
- 5Cache results as job boards typically update daily
- 6Handle multi-location jobs by checking isMultiLocation and multi_location fields
- 7Try sitemap discovery as a fallback if the widgets API is blocked
One endpoint. All Phenom People jobs. No scraping, no sessions, no maintenance.
Get API accesscurl "https://enterprise.jobo.world/api/jobs?sources=phenom people" \
-H "X-Api-Key: YOUR_KEY" 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.