Odel
ATS Jobs — open roles and hiring changes

ATS Jobs — open roles and hiring changes

Local
@vovikpJavaScriptMITUpdated Yesterday

Open jobs and hiring changes from Greenhouse, Lever, Ashby, Workable, Teamtailor, SmartRecruiters

Greenhouse, Lever, Ashby, Workable, Teamtailor Jobs API

One API for six applicant tracking systems: Greenhouse, Lever, Ashby, Workable, Teamtailor and SmartRecruiters.

Give it a company website. It finds the job board itself, returns every open role, and on every run after that returns only what changed — roles opened, roles closed, titles moved, salaries changed — plus derived hiring signals.

{ "domains": ["stripe.com", "spotify.com", "pleo.io"] }

No board tokens. No ATS knowledge required. No browser.


Two ways to run it

Hosted on ApifySelf-hosted MCP server
Setupnonenpx ats-jobs-mcp
State between runsmanagedlocal file
Scheduling, retries, storageincludedyour own
Price$1 per 1,000 jobsfree
Linkapify.com/feedworks/ats-jobs-apithis repo, mcp/

The logic is the same code in both. Pick whichever fits.


What you get

EventMeaning
job_indexedBaseline: an open role captured on the first run
job_postedA new opening appeared
job_closedAn opening disappeared
job_changedTitle, location, department or employment type changed
salary_changedCompensation changed
hiring_acceleratingThis month's postings are 2× or more the recent average
first_role_in_functionFirst ever hire in sales, AI/ML, security, data — a new budget line opened
hiring_freezePostings dropped to zero after steady hiring

Every record carries provenance: source URL, HTTP status, fetch time, job count, truncation flag and a confidence value — so an agent can verify before it acts, instead of trusting a claim.


MCP server

npx ats-jobs-mcp

Four tools, usable by any MCP client — Claude Desktop, Cursor, VS Code, your own agent:

ToolQuestion it answers
find_job_boardWhich ATS does this company use, and what is its board token?
list_jobsWhat roles are open right now?
detect_changesWhat changed since the last time I looked?
hiring_summaryWhat is this company hiring for — which functions, which locations?

Claude Desktop config:

{
  "mcpServers": {
    "ats-jobs": { "command": "npx", "args": ["-y", "ats-jobs-mcp"] }
  }
}

State lives in ~/.ats-jobs-mcp/state.json. Override with ATS_MCP_STATE.


Why it stays cheap to run continuously

Every source is polled with If-None-Match. When nothing changed, the ATS answers 304 with no body.

Measured on the hosted Actor at 512 MB:

PathCompute
Nothing changed (304)0.000344 CU per run
Baseline, 143 jobs0.001386 CU

That is why watching hundreds of companies every few hours costs cents rather than dollars — and why this project will never open a headless browser to read a job board.


What it deliberately does not do

  • No personal data. Recruiter names, emails and phone numbers are stripped at parse time and never stored.
  • No headless browser, no proxies. Only public ATS endpoints that answer with JSON.
  • No false layoffs. If a source response may be truncated by paging, job_closed events are suppressed — a paging artefact must never look like a company shutting down hiring.

Supported sources

greenhouse · lever · ashby · workable · teamtailor · smartrecruiters

Detection order: a link on the company careers page → the board token guessed from the domain → Workable short links resolved through their redirect.

Companies that cannot be resolved return a source_unresolved record explaining why, instead of failing silently.

Recruitee and Personio are not listed because they are not verified working. Personio currently answers 429 to non-browser clients; Recruitee endpoints did not resolve in testing. This project does not claim coverage it cannot deliver.


Repo layout

src/          Apify Actor: adapters, diff engine, derived signals
mcp/          MCP server — the same engine, self-hosted
tools/        discovery utilities (domain → ATS)
.actor/       Apify manifests and schemas

MIT licensed. Contributions welcome, especially new ATS adapters — the interface is one url() and one parse() function per system, see src/adapters/index.js.