Freshteam Jobs API.
HR software by Freshworks for growing companies with embedded job data attributes for easy scraping.
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 Freshteam.
- SMB focus
- HR integration
- Easy setup
- Candidate tracking
- Employee management
- Embedded data attributes
- JSON-LD structured data
- 01SMB job tracking
- 02HR software integration
- 03Growing company monitoring
How to scrape Freshteam.
Step-by-step guide to extracting jobs from Freshteam-powered career pages—endpoints, authentication, and working code.
import requests
from bs4 import BeautifulSoup
company_slug = "a1fed"
url = f"https://{company_slug}.freshteam.com/jobs"
response = requests.get(url, timeout=10)
soup = BeautifulSoup(response.content, "html.parser")
# Find all job listings with data attributes
job_elements = soup.select("a[data-portal-title]")
print(f"Found {len(job_elements)} jobs")jobs = []
for job_el in job_elements:
job = {
"title": job_el.get("data-portal-title", ""),
"location": job_el.get("data-portal-location", ""),
"job_type_id": job_el.get("data-portal-job-type", ""),
"is_remote": job_el.get("data-portal-remote-location") == "true",
"url": f"https://{company_slug}.freshteam.com{job_el.get('href', '')}",
}
# Extract display title from inner div
title_div = job_el.select_one(".job-title")
if title_div:
job["display_title"] = title_div.get_text(strip=True)
jobs.append(job)
print(f"Extracted {len(jobs)} jobs with structured data")def build_mappings(soup):
mappings = {"departments": {}, "job_types": {}, "locations": {}}
# Extract department mappings
dept_select = soup.select_one("select#department_id")
if dept_select:
for option in dept_select.select("option[value]"):
mappings["departments"][option["value"]] = option.get_text(strip=True)
# Extract job type mappings
type_select = soup.select_one("select#work_type_id")
if type_select:
for option in type_select.select("option[value]"):
mappings["job_types"][option["value"]] = option.get_text(strip=True)
# Extract location mappings
loc_select = soup.select_one("select#city_id")
if loc_select:
for option in loc_select.select("option[value]"):
mappings["locations"][option["value"]] = option.get_text(strip=True)
return mappings
mappings = build_mappings(soup)
print("Departments:", mappings["departments"])import json
def get_job_details(job_url: str) -> dict:
response = requests.get(job_url, timeout=10)
soup = BeautifulSoup(response.content, "html.parser")
# Find JSON-LD structured data
script_tag = soup.select_one('script[type="application/ld+json"]')
if script_tag:
data = json.loads(script_tag.string)
return {
"title": data.get("title"),
"description": data.get("description"),
"date_posted": data.get("datePosted"),
"employment_type": data.get("employmentType"),
"is_remote": data.get("remote") == "true",
"location": data.get("jobLocation", {}).get("address", {}),
}
return {}
# Get details for first job
if jobs:
details = get_job_details(jobs[0]["url"])
print(f"Job: {details.get('title')}")import time
def fetch_all_jobs(company_slug: str) -> list:
url = f"https://{company_slug}.freshteam.com/jobs"
jobs = []
try:
response = requests.get(url, timeout=10)
response.raise_for_status()
soup = BeautifulSoup(response.content, "html.parser")
job_elements = soup.select("a[data-portal-title]")
mappings = build_mappings(soup)
for job_el in job_elements:
job = {
"title": job_el.get("data-portal-title", ""),
"location": job_el.get("data-portal-location", ""),
"is_remote": job_el.get("data-portal-remote-location") == "true",
"url": f"https://{company_slug}.freshteam.com{job_el.get('href', '')}",
}
jobs.append(job)
except requests.RequestException as e:
print(f"Error fetching jobs: {e}")
return jobsFreshteam does not expose a public REST API. Use HTML scraping with data attributes or JSON-LD extraction instead.
Verify the company subdomain matches the actual Freshteam careers page URL. Some companies use custom domains.
Parse the select dropdown elements on the page to build ID-to-name mappings before extracting job data.
Fetch individual job detail pages and extract the JSON-LD structured data from script tags for full descriptions.
Use data-portal-* attributes which are more stable than CSS class names. These attributes are designed for client-side filtering.
- 1Use data-portal-* attributes for reliable structured data extraction
- 2Extract JSON-LD from detail pages for complete job descriptions
- 3Build ID mappings from select dropdowns for human-readable values
- 4Cache results - job boards typically update daily
- 5Use reasonable delays between requests (1-2 seconds)
- 6Validate company slug exists before bulk scraping
One endpoint. All Freshteam jobs. No scraping, no sessions, no maintenance.
Get API accesscurl "https://enterprise.jobo.world/api/jobs?sources=freshteam" \
-H "X-Api-Key: YOUR_KEY" Access Freshteam
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.