ATS Jobs API — 1.3M Jobs from 24,000+ Companies, One Search
Pricing
from $1.50 / 1,000 job listings
ATS Jobs API — 1.3M Jobs from 24,000+ Companies, One Search
One search over 1.3M open jobs from 24,000+ company career sites on Workday, Greenhouse, Lever, Ashby, SmartRecruiters, Workable and 4 more ATS, with full descriptions. No company list needed: the index is rebuilt daily. Or track named companies with only-new alerts. $2 per 1,000 jobs.
Pricing
from $1.50 / 1,000 job listings
Rating
0.0
(0)
Developer
Dmitry Melikhov
Maintained by CommunityActor stats
0
Bookmarked
1
Total users
0
Monthly active users
5 days ago
Last modified
Categories
Security
Limited permissionsShare
ATS Jobs API — 1.3M Jobs from 23,000+ Companies, One Search
1.3M open jobs from 23,000+ companies in one search. The index of every live career board we know (Workday, Greenhouse, Lever, Ashby, SmartRecruiters, Workable, Recruitee, Teamtailor, Breezy HR, Personio) is rebuilt every night, so you do not need a list of companies or career-site URLs. A search over the whole index takes about 30 seconds.
Search open jobs straight from company applicant-tracking systems. Type a job title and a location and get matching postings from ~20,000 live career boards on Greenhouse, Lever, Ashby, Workday, SmartRecruiters, Workable, Recruitee, Teamtailor, Breezy HR and Personio — or give a list of companies and track every new role they open. No login, no browser, no API keys.
- Search mode — no company list needed:
{"keywords": ["data engineer"], "locations": ["Berlin", "remote"]}. Reads a daily index of every live board, newest jobs first (vendors alternate within each day, so one ATS does not fill the page), with the full description fetched for every job delivered. - Company mode — names (
Stripe,NVIDIA), ATS boards (greenhouse:gitlab) or websites (notion.so): fetched live, with full descriptions. - Only-new monitoring — schedule it and get only postings that appeared since the last run. You pay only for new rows.
- Filters that save money — title keywords, exclusions, locations, remote-only, posted-within-N-days, ATS platform. Jobs that do not match are never charged.
- $2 per 1,000 jobs, full descriptions included. No subscription; a run start costs $0.00005.
Found it useful? Leave a ⭐ review — it helps other people find this Actor → https://apify.com/suitable_sunspot/keyless-ats-jobs-api/reviews
Who uses it
| You are | You give it | You get |
|---|---|---|
| Job seeker / job board | Title keywords + locations | Fresh postings from 20,000+ employers' own career sites, before aggregators pick them up |
| Sales / SDR team selling to growing companies | Target-account list + a daily schedule | "Acme opened 3 Data Engineer jobs" — a buying signal, every morning |
| Recruiting agency | Client and prospect companies | Every new opening with a direct apply URL |
| Investor / analyst | Watch-list companies | Hiring velocity by company, department and location |
| AI agent (MCP / API) | keywords or companies | Structured jobs in one call |
Quick start
Search every board (no company list):
{"keywords": ["machine learning", "data engineer"],"excludeKeywords": ["intern"],"locations": ["London", "remote"],"postedWithinDays": 7,"maxItems": 100}
Track specific companies — names, ATS boards or websites:
{"companies": ["Stripe", "notion", "greenhouse:gitlab", "https://nvidia.wd5.myworkdayjobs.com/NVIDIAExternalCareerSite"],"keywords": ["engineer"]}
Company names are looked up in a directory of ~35,000 public ATS boards; anything not found there is treated as a website and its ATS is detected automatically.
Monitoring mode — schedule it daily:
{"companies": ["Stripe", "Notion", "GitLab"],"onlyNewJobs": true,"stateKey": "sales-targets"}
The first run returns all current jobs (your baseline). Every next run returns only postings that appeared since — and you pay only for those rows. Works in search mode too: a saved search for "rust engineer, remote" becomes a daily alert.
Output — one row per job
{"vendor": "greenhouse","company": "GitLab","title": "Senior Backend Engineer","url": "https://job-boards.greenhouse.io/gitlab/jobs/8860302002","location": "Remote, US","department": "Engineering","employmentType": null,"postedAt": "2026-10-01T00:00:00-04:00","remote": null,"jobId": "8860302002","description": "…","salaryRaw": null,"salaryMin": null,"salaryMax": null,"salaryCurrency": null,"salaryPeriod": null,"sourceUrl": "https://boards-api.greenhouse.io/v1/boards/gitlab/jobs?content=true","fetchedAt": "2026-10-16T12:00:00+00:00","statusCode": 200}
Same schema for all ten ATS vendors. null means the vendor does not publish that field. The five salary* fields are null unless the vendor exposes a salary; Breezy HR publishes one and it is parsed into salaryMin/salaryMax (numbers), salaryCurrency (ISO code) and salaryPeriod (year/month/hour/day), with the raw text preserved in salaryRaw.
Integrations
New jobs every day → Google Sheets + Slack (n8n). Schedule the Actor with onlyNewJobs: true and one stable stateKey per watch-list: the first run is your baseline, every later run returns only the postings that appeared since — and you are not billed again for rows you already received. In n8n, chain Schedule Trigger → HTTP Request → Google Sheets (Append rows) → Slack, using the request below. Zero new jobs returns zero rows, so nothing is appended or posted.
- Method:
POST - URL:
https://api.apify.com/v2/acts/suitable_sunspot~keyless-ats-jobs-api/run-sync-get-dataset-items?timeout=180&maxTotalChargeUsd=0.1 - Header:
Authorization: Bearer <APIFY_TOKEN> - Body:
{"companyWebsites": ["stripe.com", "notion.so", "gitlab.com"],"onlyNewJobs": true,"stateKey": "sales-targets","maxItems": 200,"maxJobsPerCompany": 50,"includeDescriptions": false}
Prefer the native node? Install @apify/n8n-nodes-apify and use Run actor and get dataset with the same body. Sheet headers: detected_at, company, title, location, department, employmentType, postedAt, vendor, salaryMin, salaryMax, salaryCurrency, url, jobId.
Python (pip install apify-client):
import osfrom apify_client import ApifyClientclient = ApifyClient(os.environ["APIFY_TOKEN"])run = client.actor("suitable_sunspot~keyless-ats-jobs-api").call(run_input={"companyWebsites": ["stripe.com", "notion.so", "gitlab.com"],"onlyNewJobs": True,"stateKey": "sales-targets","maxItems": 200,"includeDescriptions": False,},max_total_charge_usd=0.10, # cost ceiling for this run)for job in client.dataset(run["defaultDatasetId"]).iterate_items():print(job["company"], "|", job["title"], "|", job["url"])
JavaScript (Node 18+):
const res = await fetch("https://api.apify.com/v2/acts/suitable_sunspot~keyless-ats-jobs-api/run-sync-get-dataset-items?timeout=180&maxTotalChargeUsd=0.1",{method: "POST",headers: { Authorization: `Bearer ${process.env.APIFY_TOKEN}`, "Content-Type": "application/json" },body: JSON.stringify({companyWebsites: ["stripe.com", "notion.so", "gitlab.com"],onlyNewJobs: true,stateKey: "sales-targets",maxItems: 200,includeDescriptions: false,}),},);const jobs = await res.json();console.log(`${jobs.length} new jobs`);
curl:
curl -sS -X POST \-H "Authorization: Bearer $APIFY_TOKEN" \-H "Content-Type: application/json" \-d '{"companyWebsites":["stripe.com","notion.so","gitlab.com"],"onlyNewJobs":true,"stateKey":"sales-targets","maxItems":200,"includeDescriptions":false}' \"https://api.apify.com/v2/acts/suitable_sunspot~keyless-ats-jobs-api/run-sync-get-dataset-items?timeout=180&maxTotalChargeUsd=0.1"
Pricing
$2.00 per 1,000 jobs delivered (event job-listing; volume discounts on higher Apify plans). You are never charged for jobs removed by your filters, errors, retries, companies where no ATS was found, jobs you already received in monitoring mode, or the coverage report. Apify platform usage is included.
Example: if your watch-list produces 300 new postings in a week, that week costs $0.60.
Coverage report (key-value store COVERAGE)
One entry per company, so you always know what you did and did not get:
{ "vendor": "greenhouse", "company": "stripe.com", "handle": "stripe","jobsFound": 200, "jobsExpected": 731, "coverageStatus": "capped","gapReason": "stopped at maxJobsPerCompany=200 (731 reported)","newJobsDelivered": 12, "detectedFrom": "stripe.com: probed greenhouse API with handle 'stripe'" }
coverageStatus: complete | partial | capped | failed | not_attempted | not_detected.
How ATS detection works
- If you paste an ATS URL (
jobs.lever.co/acme,acme.wd5.myworkdayjobs.com/External) it is parsed directly. - Otherwise the Actor reads the company site,
/careersand/jobsand looks for embedded ATS links or widgets. - As a last resort it tries the domain name as a Greenhouse, Lever or Ashby handle. A match found this way is marked "probed … with handle" in
detectedFrom— check it for companies with generic names. For exact control, passcompanieswith{vendor, handle}instead.
Limits
- Search mode reads an index rebuilt every day, so a job posted a few hours ago may appear in company mode before it reaches search. Search mode fetches descriptions only for the jobs it delivers; set
includeDescriptions: falsefor a faster, title-only search. - The board directory comes from public sources (Common Crawl board tokens via open-ats-feed and ats-scrapers, both MIT) and is re-probed daily; a company missing from it can still be reached by website or ATS URL.
- Staff-only boards (internal careers, redeployment) are left out of search results, and career-site labels are stripped from employer names (
Cba (CommBank Careers)→CBA). - Only public career boards are read. Companies using other ATS (iCIMS, Taleo, SuccessFactors…) are reported as
not_detectedand cost nothing. - Workday reports at most what its public career site shows; descriptions cost one extra request per job.
- Descriptions are fetched for every vendor (Workable includes them inline, SmartRecruiters and Breezy cost one extra request per job). Set
includeDescriptions: falseto skip them for speed. - Salary is only reported where the ATS publishes it — Breezy HR does; Greenhouse, Lever, Ashby, Workday, Workable and SmartRecruiters do not in their public feeds, so
salary*isnullthere. - Monitoring memory lives in a named key-value store
ats-jobs-state-<stateKey>in your own account; delete it to reset.
Exact sources (advanced)
| Vendor | Input | Public endpoint | Reports a total? |
|---|---|---|---|
| Greenhouse | {vendor:"greenhouse", handle} | boards-api.greenhouse.io/v1/boards/{handle}/jobs | yes |
| Lever | {vendor:"lever", handle} | api.lever.co/v0/postings/{handle} | no |
| Ashby | {vendor:"ashby", handle} | api.ashbyhq.com/posting-api/job-board/{handle} | no |
| Workday | {vendor:"workday", handle, host, site} | POST {host}/wday/cxs/{tenant}/{site}/jobs | yes |
| Personio | {vendor:"personio", handle} | {handle}.jobs.personio.de/xml | yes |
| Recruitee | {vendor:"recruitee", handle} | {handle}.recruitee.com/api/offers/ | no |
| Teamtailor | {vendor:"teamtailor", handle} | {handle}.teamtailor.com/jobs.json | no |
| Workable | {vendor:"workable", handle} | POST apply.workable.com/api/v3/accounts/{handle}/jobs | yes |
| SmartRecruiters | {vendor:"smartrecruiters", handle} | api.smartrecruiters.com/v1/companies/{handle}/postings | yes |
| Breezy HR | {vendor:"breezy", handle} | {handle}.breezy.hr/json | no |
Feedback
Missing an ATS or a field you need? Open an issue on the Actor page.
Run tests
$.venv/bin/python -m pytest tests/ -q