Skip to content
Engineering Guide · Python & Node.js ATS Scraper8 min read·Updated 2026-11-04

How to Scrape Workday, Greenhouse, Lever & Ashby Job Postings in Python (2026 Guide)

A senior engineer's blueprint comparing direct ATS board scraping (Greenhouse JSON boards, Lever postings API, Ashby GraphQL/REST, and Workday myworkdayjobs.com CXS endpoints) against a single unified REST call across 434 ATS & corporate career connectors.

1 Credit = 1 Job Record ($0.199–$0.76 / 1K Jobs) · 0 Credits for Empty Searches · 434 ATS & Career Sources

Instant Quickstart · Copy & Run in 30 Seconds

Cursor-Paginated Python & Node.js ATS Job Harvester

Execute in Live Playground →
import time
import requests

API_KEY = "jp_live_your_api_key"
BASE_URL = "https://api.jobpostingsapi.com/v1/jobs/search"

def fetch_ats_jobs(sources: str = "workday,greenhouse,lever,ashby", max_pages: int = 5):
    cursor = None
    jobs = []
    for page in range(max_pages):
        params = {
            "source": sources,
            "q": "engineer",
            "remote": "true",
            "posted_since": "7d",
            "limit": 25,
        }
        if cursor:
            params["cursor"] = cursor

        res = requests.get(
            BASE_URL,
            headers={"x-api-key": API_KEY},
            params=params,
            timeout=20,
        )
        res.raise_for_status()
        payload = res.json()
        batch = payload.get("data", [])
        jobs.extend(batch)

        meta = payload.get("meta", {})
        if not meta.get("has_more") or not meta.get("next_cursor"):
            break
        cursor = meta["next_cursor"]
        time.sleep(0.2)
    return jobs

if __name__ == "__main__":
    results = fetch_ats_jobs()
    for j in results[:5]:
        print(f"[{j['source']['name']}] {j['company']['name']} — {j['title']} ({j['url']})")

Key Engineering Takeaways (TL;DR)

  • ✓Greenhouse, Lever, and Ashby expose public JSON/GraphQL endpoints per employer board, but require maintaining thousands of board tokens and separate HTML/location parsers.
  • ✓Workday (myworkdayjobs.com) splits employers across wd1, wd3, wd5, and wd12 subdomains with dynamic tenant paths and undocumented CXS POST pagination payloads.
  • ✓A single GET /v1/jobs/search?source=workday,greenhouse,lever,ashby call returns normalized JSON with AI-extracted USD salaries, remote work modes, seniority, and canonical skills at 1 Credit ($0.000199–$0.00076) per job.
  • ✓Use GET /v1/companies/{slug}/jobs?refresh=true to trigger an on-demand ETag board verification when you need zero-lag confirmation for a specific company.

1. Anatomy of Direct ATS Endpoints: Why DIY Scrapers Break at Scale

Before writing a custom Python crawler, understand how the Big Four enterprise ATS platforms serve job listings and where maintenance bottlenecks emerge.

Technical comparison of raw ATS board protocols vs unified JobPostings API
ATS PlatformRaw Endpoint PatternMain Scraping BottleneckUnified API Filter
WorkdayPOST https://{tenant}.wd5.myworkdayjobs.com/wday/cxs/{tenant}/{site}/jobsRequires tenant + cluster (wd1–wd12) + site slug discovery; list call omits full job description HTMLsource=workday (1,280+ employer portals)
GreenhouseGET https://boards-api.greenhouse.io/v1/boards/{token}/jobs?content=trueUnstructured HTML entities in content; free-text location strings without ISO country or remote flagssource=greenhouse (6,294+ active boards)
LeverGET https://api.lever.co/v0/postings/{site}?mode=jsonNested lists[] array for requirements; inconsistent compensation fields across employerssource=lever (2,135+ active boards)
AshbyGET https://api.ashbyhq.com/posting-api/job-board/{board}?includeCompensation=trueBoard slug differs from company domain; custom compensation tiers require currency normalizationsource=ashby (2,684+ active boards)

2. Production Python Scraper: Paginating Across Workday, Greenhouse, Lever & Ashby

Instead of maintaining 12,000+ separate board URLs and four parser schemas, query all four enterprise ATS ecosystems in one cursor-paginated Python loop.

Cursor-Paginated Python & Node.js ATS Job Harvester

Fetch newly posted software & AI engineering roles from Workday, Greenhouse, Lever, and Ashby with normalized USD compensation:

curl "https://api.jobpostingsapi.com/v1/jobs/search?source=workday,greenhouse,lever,ashby&q=engineer&remote=true&posted_since=7d&limit=25" \
  -H "x-api-key: jp_live_your_api_key"

3. Cost & Engineering Maintenance Breakdown: DIY ATS Crawlers vs. JobPostings API

Running headless browsers and residential proxies for Workday, iCIMS, and Taleo alongside 10,000+ Greenhouse/Lever/Ashby boards quickly exceeds $500/month in infra alone.

  • Board Discovery & Slug Churn: Companies rebrand, migrate from Lever to Ashby, or change Workday tenant URLs every week. JobPostings API continuously maps 434 ATS & career-site connectors to canonical company domains.
  • Zero Proxy or Headless Browser Overhead: Pay $19/mo for 25,000 Credits ($0.76/1K jobs) or $25 non-expiring PAYG instead of managing Playwright worker fleets and residential proxy pools.
  • Built-In Dead Link & Closed Job Detection: Every ATS requisition is re-verified on a 1h–4h cadence. Closed roles emit a closed event on GET /v1/feeds/closed so your database never serves 404 application links.

Interactive Engineering Workbench · GET /v1/jobs/search

Verify real-time latency, pagination math & JSON schema

5,000 jobs/day
2,000 records/day
500 checks/day
HTTP Calls / Day
570
100 jobs/page batching
ATS Sources Covered
434 Sources
1 JSON schema
Empty Search Fee
0 Credits
$0.00 for 0 results
Estimated Monthly Pipeline Cost (30 Days)
$44.78/ mo at Scale rate ($74.25 at Pro rate)
Monthly consumption: 225,000 Credits (7,500 Credits/day)
JobPostings API (Scale $0.199/1K):$44.78 / mo
Legacy Enterprise Job Feeds:$1012.50 / mo
Empty search / 4xx error fee:$0.00 (0 Credits)

Frequently Asked Questions

Why is Workday harder to scrape in Python than Greenhouse or Lever?
Greenhouse and Lever expose single-call public JSON endpoints per employer slug. Workday hosts employers across regional clusters (wd1, wd3, wd5, wd12) and requires a POST request to /wday/cxs/{tenant}/{site}/jobs for pagination plus a separate GET request per job slug to retrieve the full HTML description. JobPostings API normalizes 1,280+ Workday portals into the exact same schema as Greenhouse, Lever, and Ashby.
How do I find which ATS a company uses from its domain?
Call GET /v1/companies/{slug} with a company domain (e.g., stripe.com or anthropic.com) or use our free interactive Company ATS & Career URL Detector at /tools/ats-detector.
How many Credits does a multi-ATS search query consume?
1 Credit per returned job record ($0.000199 to $0.00076 depending on tier). If your filter matches 0 jobs, 0 Credits are deducted.