Skip to main content

Jobs

Job-market data: normalized ATS job listings across Greenhouse, Lever, Ashby, and Workday, cross-board keyword search, Levels.fyi salary bands, and the async job status endpoints that power Pry's own background work.

What it scrapes

SourceData
ATS boards (greenhouse/lever/ashby/workday)Normalized job postings per company (title, location, department, URL, posted date)
Multiple ATS boardsCross-board keyword search (q matches title or location)
Levels.fyiPer-level salary bands (total comp, base, stock, bonus) by company + role
Pry's async queueJob status and results (GET /v1/job/{job_id}) + Pryfile job listing

Endpoints

Router: routers/jobs.py · tag: Jobs

MethodPathSummary
GET/v1/job/{job_id}Async job status + result
GET/v1/jobsList jobs in a Pryfile (path default pry.yml)
GET/v1/jobs/searchCross-board keyword search (q, limit 1–100, default 20)
GET/v1/jobs/salary/{company}Salary bands from Levels.fyi (role default software_engineer)
GET/v1/jobs/{board}/{company}ATS job listings (limit 1–500, default 50)
GET/v1/jobs/{board}/job/{job_id}One job's full detail (company query param required)

Routing note: /v1/jobs/search and /v1/jobs/salary/{company} are registered before the parametrized /v1/jobs/{board}/{company} route so the static segments are never swallowed by the {board} match.

GET /v1/jobs/{board}/{company}

Supported boards: greenhouse, lever, ashby, workday. Company is the company slug on that board (e.g. stripe).

curl -X GET "http://localhost:8005/v1/jobs/greenhouse/stripe?limit=5" \
-H "Authorization: Bearer <key>"

Response (200):

{
"success": true,
"board": "greenhouse",
"company": "stripe",
"data": [
{
"id": "1234567",
"title": "Software Engineer, Backend",
"location": "Remote (US)",
"department": "Engineering",
"posted_at": "2026-08-10",
"url": "https://boards.greenhouse.io/stripe/jobs/1234567"
}
]
}

GET /v1/jobs/search

curl -X GET "http://localhost:8005/v1/jobs/search?q=backend&limit=10" \
-H "Authorization: Bearer <key>"

Response (200):

{
"success": true,
"data": [
{
"board": "greenhouse",
"company": "stripe",
"title": "Software Engineer, Backend",
"location": "Remote (US)",
"url": "https://boards.greenhouse.io/stripe/jobs/1234567"
}
]
}

GET /v1/jobs/salary/{company}

curl -X GET "http://localhost:8005/v1/jobs/salary/stripe?role=software_engineer" \
-H "Authorization: Bearer <key>"

Response (200):

{
"success": true,
"data": {
"company": "Stripe",
"role": "software_engineer",
"levels": [
{
"level": "L3",
"total_comp": 210000,
"base": 160000,
"stock": 35000,
"bonus": 15000
},
{
"level": "L4",
"total_comp": 280000,
"base": 190000,
"stock": 70000,
"bonus": 20000
}
]
}
}

Async job status

curl -X GET "http://localhost:8005/v1/job/abc123" \
-H "Authorization: Bearer <key>"

Response (200):

{
"success": true,
"data": {
"id": "abc123",
"status": "completed",
"result": {"pages": 12}
}
}

GET /v1/jobs?path=pry.yml lists all jobs defined in a Pryfile with their current status and configuration.

MCP tools

No dedicated MCP tool for the jobs endpoints yet. The pry_template catalog includes job-board templates (e.g. linkedin) — search with pry_search_templates and run with pry_template.

Who uses this

  • Talent intelligence — track a competitor's open roles and hiring velocity by board + company.
  • Recruiters / market researchers — salary bands from Levels.fyi for comp benchmarking.
  • Job aggregators — cross-board search as a lightweight feed source.
  • Internal automationGET /v1/job/{job_id} to poll Pry's own async scrape/crawl jobs.

Next steps