All platforms

Paycom Jobs API.

HR and payroll platform with integrated recruiting, onboarding, and talent management features.

Paycom
Live
60K+jobs indexed monthly
<3haverage discovery time
1hrefresh interval
Companies using Paycom
NEW ASPEN MANAGEMENT LLCMid to large 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 Paycom.

Data fields
  • HCM integration
  • Payroll data
  • Onboarding
  • Time tracking
  • Compliance management
  • Talent acquisition
Use cases
  1. 01Enterprise job aggregation
  2. 02HR compliance monitoring
  3. 03Payroll-integrated recruiting
Trusted by
NEW ASPEN MANAGEMENT LLCMid to large enterprises
DIY GUIDE

How to scrape Paycom.

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

RESTadvancedUndocumented throttling; use delays between requestsAuth required

Extract the portal key from the career page URL

Each Paycom company has a unique 32-character hexadecimal portal key in their career page URL. Extract this key to identify the company's job board.

Step 1: Extract the portal key from the career page URL
import re

career_url = "https://www.paycomonline.net/v4/ats/web.php/portal/A7EA16ADA834B1F889CBB30B17AEB9A9/career-page"

# Extract the 32-character hex portal key
match = re.search(r'portal/([A-F0-9]+)/career-page', career_url)
if match:
    portal_key = match.group(1)
    print(f"Portal Key: {portal_key}")

Fetch the career page and extract the JWT token

The Paycom API requires a JWT token for authentication. This token is embedded in the HTML of the career page and must be extracted using a regex pattern before making API requests.

Step 2: Fetch the career page and extract the JWT token
import re
import requests

career_url = "https://www.paycomonline.net/v4/ats/web.php/portal/A7EA16ADA834B1F889CBB30B17AEB9A9/career-page"

# Fetch the career page HTML
response = requests.get(career_url)
html = response.text

# Extract JWT token from the embedded JavaScript
jwt_match = re.search(r'"(eyJ[A-Za-z0-9_-]+.[A-Za-z0-9_-]+.[A-Za-z0-9_-]+)"', html)
if jwt_match:
    jwt_token = jwt_match.group(1)
    print(f"JWT Token: {jwt_token[:50]}...")
else:
    print("JWT token not found in page")

Fetch job listings from the search API

Use the job-posting-previews search endpoint to retrieve job listings. The API supports pagination via skip/take parameters and returns truncated descriptions in the preview.

Step 3: Fetch job listings from the search API
import requests

jwt_token = "YOUR_JWT_TOKEN"
url = "https://portal-applicant-tracking.us-cent.paycomonline.net/api/ats/job-posting-previews/search"

headers = {
    "authorization": jwt_token,
    "content-type": "application/json",
    "locale": "en-US",
    "origin": "https://www.paycomonline.net",
    "referer": "https://www.paycomonline.net/",
}

payload = {
    "skip": 0,
    "take": 100,  # Fetch up to 100 jobs per request
    "filtersForQuery": {
        "distanceFrom": 0,
        "workEnvironments": [],
        "positionTypes": [],
        "educationLevels": [],
        "categories": [],
        "travelTypes": [],
        "shiftTypes": [],
        "otherFilters": [],
        "keywordSearchText": "",
        "location": "",
        "sortOption": ""
    }
}

response = requests.post(url, headers=headers, json=payload)
data = response.json()

print(f"Total jobs: {data.get('jobPostingPreviewsCount', 0)}")
for job in data.get('jobPostingPreviews', []):
    print(f"  - [{job['jobId']}] {job['jobTitle']} ({job['locations']})")

Fetch full job details for each listing

The listings API returns truncated descriptions. To get the full job description and qualifications, make a separate GET request for each job ID.

Step 4: Fetch full job details for each listing
import requests

jwt_token = "YOUR_JWT_TOKEN"
job_id = 216798
portal_key = "A7EA16ADA834B1F889CBB30B17AEB9A9"

url = f"https://portal-applicant-tracking.us-cent.paycomonline.net/api/ats/job-postings/{job_id}"

headers = {
    "authorization": jwt_token,
    "content-type": "application/json",
    "locale": "en-US",
    "origin": "https://www.paycomonline.net",
    "referer": "https://www.paycomonline.net/",
}

response = requests.get(url, headers=headers)
data = response.json()

job = data.get("jobPosting", {})
print({
    "id": job.get("jobId"),
    "title": job.get("jobTitle"),
    "location": job.get("location"),
    "position_type": job.get("positionType"),
    "remote_type": job.get("remoteType"),
    "salary_range": job.get("salaryRange"),
    "is_hot_job": job.get("isHotJob"),
    "apply_available": job.get("applyAvailable"),
    "description_length": len(job.get("description", "")),
})

# Construct the job URL for reference
job_url = f"https://www.paycomonline.net/v4/ats/web.php/portal/{portal_key}/jobs/{job_id}"
print(f"Job URL: {job_url}")

Handle pagination for large job boards

For companies with more than 100 jobs, use the skip parameter to paginate through all results. Calculate total pages from the jobPostingPreviewsCount field.

Step 5: Handle pagination for large job boards
import requests
import time

jwt_token = "YOUR_JWT_TOKEN"
url = "https://portal-applicant-tracking.us-cent.paycomonline.net/api/ats/job-posting-previews/search"

headers = {
    "authorization": jwt_token,
    "content-type": "application/json",
    "locale": "en-US",
    "origin": "https://www.paycomonline.net",
    "referer": "https://www.paycomonline.net/",
}

all_jobs = []
skip = 0
take = 100

while True:
    payload = {
        "skip": skip,
        "take": take,
        "filtersForQuery": {
            "distanceFrom": 0,
            "workEnvironments": [],
            "positionTypes": [],
            "educationLevels": [],
            "categories": [],
            "travelTypes": [],
            "shiftTypes": [],
            "otherFilters": [],
            "keywordSearchText": "",
            "location": "",
            "sortOption": ""
        }
    }

    response = requests.post(url, headers=headers, json=payload)
    data = response.json()

    jobs = data.get("jobPostingPreviews", [])
    all_jobs.extend(jobs)

    total_count = data.get("jobPostingPreviewsCount", 0)
    print(f"Fetched {len(jobs)} jobs (total: {len(all_jobs)}/{total_count})")

    if len(all_jobs) >= total_count or len(jobs) == 0:
        break

    skip += take
    time.sleep(0.5)  # Rate limiting delay

print(f"\nTotal jobs collected: {len(all_jobs)}")

Handle JWT token expiration and refresh

JWT tokens expire after several hours. For long-running scraping sessions, implement token refresh logic by re-fetching the career page when the API returns a 401 error.

Step 6: Handle JWT token expiration and refresh
import re
import requests

def get_fresh_jwt_token(portal_key: str) -> str:
    """Fetch career page and extract a fresh JWT token."""
    career_url = f"https://www.paycomonline.net/v4/ats/web.php/portal/{portal_key}/career-page"
    response = requests.get(career_url, timeout=15)
    response.raise_for_status()

    jwt_match = re.search(r'"(eyJ[A-Za-z0-9_-]+.[A-Za-z0-9_-]+.[A-Za-z0-9_-]+)"', response.text)
    if not jwt_match:
        raise ValueError("JWT token not found in page")
    return jwt_match.group(1)

def fetch_jobs_with_retry(portal_key: str, max_retries: int = 2) -> list:
    """Fetch jobs with automatic token refresh on 401 errors."""
    jwt_token = get_fresh_jwt_token(portal_key)
    url = "https://portal-applicant-tracking.us-cent.paycomonline.net/api/ats/job-posting-previews/search"

    headers = {
        "authorization": jwt_token,
        "content-type": "application/json",
        "locale": "en-US",
        "origin": "https://www.paycomonline.net",
        "referer": "https://www.paycomonline.net/",
    }

    for attempt in range(max_retries + 1):
        response = requests.post(url, headers=headers, json={"skip": 0, "take": 100, "filtersForQuery": {}})

        if response.status_code == 401:
            print(f"Token expired, refreshing (attempt {attempt + 1})...")
            jwt_token = get_fresh_jwt_token(portal_key)
            headers["authorization"] = jwt_token
            continue

        response.raise_for_status()
        return response.json().get("jobPostingPreviews", [])

    raise Exception("Failed to fetch jobs after token refresh")

# Usage
portal_key = "A7EA16ADA834B1F889CBB30B17AEB9A9"
jobs = fetch_jobs_with_retry(portal_key)
print(f"Retrieved {len(jobs)} jobs")
Common issues
criticalJWT token extraction fails

The token is embedded in the HTML and may change location. Ensure your regex pattern matches the full JWT format (eyJ...). If the page structure changes, inspect the HTML source to find the new token location.

highAPI returns 401 Unauthorized

JWT tokens expire after several hours. Re-fetch the career page and extract a fresh token. Always extract the token at the start of each scraping session.

highPortal key not found or invalid

Verify the 32-character hex key is correct. Keys may change if a company reconfigures their Paycom instance. Use search engines or the Wayback Machine to find current portal keys.

mediumRate limiting or blocked requests

Add delays between API requests (0.5-1 second). Ensure the origin and referer headers are set correctly. For high-volume scraping, consider using residential proxies.

mediumMissing job description in listings

The listings API returns truncated descriptions. Always fetch full job details using the job-postings endpoint for complete description and qualifications fields.

lowJob has multiple locations

Check the secondaryLocations array and the locations field which may contain multiple entries separated by semicolons. Parse these to get all location options.

Best practices
  1. 1Extract a fresh JWT token at the start of each scraping session
  2. 2Use take=100 to minimize pagination requests for large job boards
  3. 3Include proper origin and referer headers in all API requests
  4. 4Fetch full job details separately as listings return truncated descriptions
  5. 5Handle HTML content in description and qualifications fields
  6. 6Implement token refresh logic for long-running scraping sessions
Or skip the complexity

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

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

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