All platforms

ApplicantPro Jobs API.

Tap a public JSON API to pull salary ranges, departments, and full descriptions from any ApplicantPro careers board — no auth required, with a global sitemap index for discovering every isolved Talent Acquisition company.

Get API access
ApplicantPro
Live
30K+jobs indexed monthly
<3haverage discovery time
1hrefresh interval
Companies using ApplicantPro
Harvard BioscienceNBMETaco John'sKneaders Bakery
Developer tools

Try the API.

Test Jobs and Feed 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 ApplicantPro.

Data fields
  • Structured Pay Ranges
  • Department & Classification
  • Employment & Workplace Type
  • HTML & Plain-Text Descriptions
  • Benefits & Salary Details
  • Posting & Closing Dates
Use cases
  1. 01SMB Job Aggregation
  2. 02Multi-Company Board Discovery
  3. 03Salary Benchmarking
  4. 04Recruitment Market Research
Trusted by
Harvard BioscienceNBMETaco John'sKneaders Bakery
DIY GUIDE

How to scrape ApplicantPro.

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

RESTintermediateNo published limits; Jobo scrapes at ~1 request / 2s with a single concurrent connectionNo auth

Extract the site ID from the careers page

ApplicantPro requires a site ID (domain_id) embedded in the page HTML. Fetch the careers page and extract this ID using regex before making API calls.

Step 1: Extract the site ID from the careers page
import requests
import re
from urllib.parse import urlparse

def get_site_id(subdomain: str) -> str | None:
    url = f"https://{subdomain}.applicantpro.com/jobs/"
    response = requests.get(url, timeout=10)
    response.raise_for_status()

    # Extract domain_id from embedded JavaScript
    match = re.search(r'"domain_id"\s*:\s*"(\d+)"', response.text)
    if match:
        return match.group(1)
    return None

site_id = get_site_id("harvardbioscience")
print(f"Site ID: {site_id}")  # Output: Site ID: 11099

Fetch all job listings

Use the listings API endpoint with the site ID to retrieve all active jobs. The getParams query parameter must be a URL-encoded JSON object with display options.

Step 2: Fetch all job listings
import requests
import json
from urllib.parse import quote

subdomain = "harvardbioscience"
site_id = "11099"

get_params = {
    "isInternal": 0,
    "showLocation": 1,
    "showEmploymentType": 1,
    "chatToApplyButton": "0"
}

# URL-encode the JSON params
encoded_params = quote(json.dumps(get_params))
listings_url = f"https://{subdomain}.applicantpro.com/core/jobs/{site_id}?getParams={encoded_params}"

headers = {
    "Accept": "application/json",
    "Referer": f"https://{subdomain}.applicantpro.com/jobs/"
}
response = requests.get(listings_url, headers=headers, timeout=10)
data = response.json()

jobs = data.get("data", {}).get("jobs", [])
job_count = data.get("data", {}).get("jobCount", 0)
print(f"Found {len(jobs)} jobs (API reports {job_count} total)")

Parse job metadata from listings

Extract job fields from the listings response. The API returns comprehensive metadata including salary, location, department, and dates, but NOT job descriptions.

Step 3: Parse job metadata from listings
for job in jobs:
    print({
        "id": job.get("id"),
        "title": job.get("title"),
        "location": job.get("jobLocation"),
        "city": job.get("city"),
        "state": job.get("stateName"),
        "country": job.get("iso3"),
        "department": job.get("orgTitle"),
        "classification": job.get("classification"),
        "employment_type": job.get("employmentType"),
        "workplace_type": job.get("workplaceType"),
        "pay_type": job.get("payType"),
        "pay_details": job.get("payDetails"),
        "min_salary": job.get("minSalary"),
        "max_salary": job.get("maxSalary"),
        "job_url": job.get("jobUrl"),
        "posted_date": job.get("startDateRef"),
        "expiry_date": job.get("endDateRef"),
    })

Fetch job details for descriptions

Make a separate API call for each job to get the full description. The details endpoint returns both HTML and plain text descriptions, plus benefits information not available in listings.

Step 4: Fetch job details for descriptions
import time

def get_job_details(subdomain: str, site_id: str, job_id: int) -> dict:
    url = f"https://{subdomain}.applicantpro.com/core/jobs/{site_id}/{job_id}/job-details"
    headers = {
        "Accept": "application/json",
        "Referer": f"https://{subdomain}.applicantpro.com/jobs/{job_id}"
    }
    response = requests.get(url, headers=headers, timeout=10)
    response.raise_for_status()
    return response.json().get("data", {})

# Fetch details for first job with rate limiting
if jobs:
    details = get_job_details(subdomain, site_id, jobs[0]["id"])
    print({
        "id": details.get("id"),
        "title": details.get("title"),
        "city": details.get("city"),
        "description_html": details.get("advertisingDescriptionHtml", "")[:200],
        "description_plain": details.get("advertisingDescription", "")[:200],
        "benefits": details.get("benefits"),
        "zip_code": details.get("jobBoardZip"),
        "pay_details": details.get("payDetails"),
    })
    time.sleep(1.0)  # Be respectful with rate limiting

Handle edge cases and errors

Handle missing site IDs, empty job lists, and various date formats returned by the API. Dates can appear as 'Jan 23, 2026' or '23-Jan-2026'.

Step 5: Handle edge cases and errors
def safe_extract(subdomain: str) -> list[dict]:
    try:
        site_id = get_site_id(subdomain)
        if not site_id:
            print(f"Could not find site ID for {subdomain}")
            return []

        get_params = {"isInternal": 0, "showLocation": 1}
        encoded_params = quote(json.dumps(get_params))
        url = f"https://{subdomain}.applicantpro.com/core/jobs/{site_id}?getParams={encoded_params}"
        response = requests.get(url, headers={"Accept": "application/json"}, timeout=10)
        response.raise_for_status()

        data = response.json()
        if not data.get("success"):
            print(f"API returned error for {subdomain}")
            return []

        return data.get("data", {}).get("jobs", [])
    except requests.RequestException as e:
        print(f"Request failed for {subdomain}: {e}")
        return []

jobs = safe_extract("harvardbioscience")

Discover companies via sitemap

Use the global sitemap index to discover all ApplicantPro-powered companies. This is useful for building a comprehensive job database across multiple organizations.

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

# Global sitemap index lists all ApplicantPro companies
sitemap_index_url = "https://feeds.applicantpro.com/site_map_index.xml"
response = requests.get(sitemap_index_url, timeout=10)
root = ET.fromstring(response.content)

# Extract company sitemap URLs
namespaces = {"ns": "http://www.sitemaps.org/schemas/sitemap/0.9"}
company_sitemaps = []
for sitemap in root.findall("ns:sitemap", namespaces):
    loc = sitemap.find("ns:loc", namespaces)
    if loc is not None:
        company_sitemaps.append(loc.text)

print(f"Found {len(company_sitemaps)} company sitemaps")

# Parse individual company sitemap for job URLs
def parse_company_sitemap(sitemap_url: str) -> list[str]:
    response = requests.get(sitemap_url, timeout=10)
    root = ET.fromstring(response.content)
    job_urls = []
    for url in root.findall("ns:url", namespaces):
        loc = url.find("ns:loc", namespaces)
        if loc is not None and "/jobs/" in loc.text:
            job_urls.append(loc.text)
    return job_urls

# Example: Get jobs from first company sitemap
if company_sitemaps:
    jobs = parse_company_sitemap(company_sitemaps[0])
    print(f"Found {len(jobs)} job URLs in first sitemap")
Common issues
criticalSite ID (domain_id) not found in page HTML

The page structure may have changed. Try alternative regex patterns or look for the domain_id in script tags within the courierCurrentRouteData object. Some companies use custom domains that redirect to ApplicantPro.

highJob descriptions missing from listings response

The listings API does not include descriptions. You must make a separate call to the job-details endpoint for each job to get the full description and benefits.

mediumCustom domain redirects not handled

Some companies use custom domains that redirect to ApplicantPro. Follow redirects and extract the actual subdomain from the final URL (host ending in .applicantpro.com) before pulling the site ID.

lowEmpty jobs array returned

Some companies may have no active postings. Check the jobCount field in the response and handle empty arrays gracefully in your code.

lowInconsistent date formats between endpoints

Dates appear in different formats across endpoints (e.g. 'Jan 23, 2026' in listings vs '23-Jan-2026' in details). Use a flexible parser like dateutil to handle both.

mediumRate limiting or temporary blocks

Unthrottled requests can return HTTP 403 or 429. Keep a single concurrent connection and pause 1-2 seconds between requests, especially for per-job detail fetches.

lowSalary values are empty or malformed

Salary fields (minSalary, maxSalary) are strings and may be empty. Always check for truthy values before parsing; freeform pay info is often in payDetails as text rather than structured numbers.

Best practices
  1. 1Cache the site ID per subdomain — the careers-page HTML only needs fetching once
  2. 2Prefer advertisingDescriptionHtml, falling back to advertisingDescription then description
  3. 3Throttle to roughly one request every 1-2 seconds and cap concurrent detail fetches
  4. 4Use the jobUrl field from the response, falling back to a constructed /jobs/{id} URL
  5. 5Pull benefits and ZIP code from the details endpoint — they are absent from listings
  6. 6Discover new company boards through the global sitemap index at feeds.applicantpro.com
Or skip the complexity

One endpoint. All ApplicantPro jobs. No scraping, no sessions, no maintenance.

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

Access ApplicantPro
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