ATS Jobs by Domain: Greenhouse, Lever and Ashby avatar

ATS Jobs by Domain: Greenhouse, Lever and Ashby

Pricing

from $1.40 / 1,000 job postings

Go to Apify Store
ATS Jobs by Domain: Greenhouse, Lever and Ashby

ATS Jobs by Domain: Greenhouse, Lever and Ashby

Returns every live job opening a company posts on its own Greenhouse, Lever, Ashby, Workable, SmartRecruiters or Recruitee board, from just its domain. One JSON record per job (title, department, location, remote flag, employment type, posted date, apply URL), plus which ATS each company uses.

Pricing

from $1.40 / 1,000 job postings

Rating

0.0

(0)

Developer

Omar Nagy

Omar Nagy

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

a month ago

Last modified

Security

Limited permissions

Share

ATS Jobs by Domain gets live ATS jobs straight from a company's own Greenhouse, Lever, Ashby, Workable, SmartRecruiters or Recruitee board, starting from nothing more than the company's domain. Paste stripe.com, spotify.com and posthog.com and you get their Greenhouse jobs, Lever jobs and Ashby jobs in one dataset, as clean JSON: title, department, location, remote flag, employment type, posting date and apply URL.

It also tells you which applicant tracking system each company uses, so one run maps a whole target account list: who is hiring, on which ATS, and how many roles are open.

It reads each vendor's public JSON job board API, the same data the company's hosted job board shows. No browser, no proxy, no login and no per-board setup.

What you get

  • One job record per live opening, with a stable record_key you can upsert on.
  • One resolution record per company you asked about: the ATS it uses, the board slug, how many jobs are open, how sure the match is, and a plain reason for any company that did not resolve. Nothing disappears silently.
  • An OUTPUT summary in the run's key-value store with the delivered and charged counts.

Who it is for

  • Sales and recruiting teams who want hiring signals for an account list: which companies are hiring, for which teams, and where.
  • Job boards and newsletters that pull fresh listings for a curated set of companies, from the source rather than from aggregator reposts.
  • Founders and analysts tracking which teams a competitor is staffing up.
  • AI agents that need to answer "is Stripe hiring backend engineers in Dublin?" from the company's own board, through the Apify MCP server (see below).

How to get ATS jobs from a list of company domains

  1. Put your companies in Company domains or names, one per line. A domain (stripe.com), a careers URL or a plain name all work.
  2. Optionally set the role filters (employment type, job title pattern) and Max jobs per company.
  3. Run it. Each company is resolved to its board, the newest openings are fetched, and the results land in the dataset as each company finishes.
  4. Download the Jobs or Resolutions view as JSON, CSV or Excel, or read it from the API.

Under the hood, each company goes through the same steps:

  1. The domain becomes board slug candidates: https://www.stripe.com/jobs becomes stripe.
  2. The six ATS endpoints are probed in a fixed order until a board with live openings answers.
  3. The board is checked against the company: its job links, its published company name, or the company's careers page must agree. A board whose job links or company name point somewhere else is not used.
  4. If nothing is found, the company's own /careers page and homepage are read for a job board link. This resolves companies whose slug is not their domain: oysterhr.com publishes on Ashby as oyster.
  5. The board is paged deterministically and every opening becomes one flat record.

Input

This is the prefilled example. It returns 60 jobs and 3 resolution records in a few seconds.

{
"mode": "jobs",
"companies": ["stripe.com", "spotify.com", "posthog.com"],
"maxJobsPerCompany": 25,
"includeDescription": true,
"descriptionMaxChars": 600,
"includeResolutionRecords": true
}
FieldTypeDefaultNotes
modejobs or resolvejobsresolve only reports which ATS each company uses and how many jobs it has, without fetching them.
companiesarray of stringsRequired. Domain, URL or name. A job board URL such as https://jobs.lever.co/spotify is read as that board. Up to 500 per run.
maxJobsPerCompanyinteger 1 to 100050Newest jobs first, counted after the role filters.
employmentTypeFilterarray of stringsnoneKeep only these employment types, for example ["Contract", "Freelance", "Part-time"].
titleRegexstringnoneKeep only titles matching this case-insensitive regular expression. Max 200 characters.
includeDescriptionbooleantrueAdds the plain text description.
descriptionMaxCharsinteger 0 to 2000012000 keeps the full text.
includeResolutionRecordsbooleantrueWrites the resolution records in jobs mode. Always on in resolve mode.
maxCompaniesinteger 1 to 500100How many entries of the list are processed. Entries past it come back as input_error records and are not charged.
resolveViaCareersPagebooleantrueRead the careers page when slug guessing finds nothing.

Filtering for contract, freelance and part-time roles

{
"mode": "jobs",
"companies": ["wikimedia.org", "mozilla.org", "khanacademy.org"],
"employmentTypeFilter": ["Contract", "Freelance", "Part-time"],
"titleRegex": "(contract|fractional|freelance|part[- ]time|interim)",
"maxJobsPerCompany": 50
}
  • With both filters set, a job is kept if it matches either one. Greenhouse publishes no employment type at all, so requiring both would silently drop every Greenhouse result from a contract search.
  • Filters run before the per-company limit, so maxJobsPerCompany counts matching jobs. On SmartRecruiters, a filtered run scans up to 2,000 postings per board to find the matches.
  • An invalid titleRegex stops the run before any board is read, with an input_error record and nothing charged.

When the slug does not match the domain

When you already know the board, skip the guessing with an ats:slug entry. Ubisoft is on SmartRecruiters as Ubisoft2, which no guess from ubisoft.com will find:

{ "mode": "jobs", "companies": ["smartrecruiters:Ubisoft2", "workable:huggingface", "lever:spotify"] }

Valid prefixes: greenhouse, lever, ashby, workable, smartrecruiters, recruitee. An explicit board is taken as final, so no other system and no careers page is tried for that entry.

Output

Job and resolution records share one dataset, split by the type field, with a saved Jobs view and a Resolutions view.

A job record

Real output from the prefilled example, run on 8 October 2026. The description is shortened here.

{
"type": "job",
"company_input": "stripe.com",
"company": "Stripe",
"ats": "greenhouse",
"ats_slug": "stripe",
"record_key": "greenhouse:stripe:8248086",
"job_id": "8248086",
"title": "Sales Development Representative (Spanish fluency)",
"department": "1132 AMER Sales Development Reps",
"location_raw": "Chicago, IL",
"city": "Chicago",
"country": "United States",
"country_code": "US",
"is_remote": false,
"workplace_type": "unknown",
"employment_type": null,
"posted_at": "2026-10-07T21:45:35.000Z",
"updated_at": "2026-10-07T23:02:27.000Z",
"job_url": "https://stripe.com/jobs/search?gh_jid=8248086",
"apply_url": "https://stripe.com/jobs/search?gh_jid=8248086",
"description": "About the team\n\nNote: This role is an in-office position, based in our Chicago, IL office.\n\nAs a Sales Development Representative (SDR) at Stripe, you’ll work in a customer-facing role...",
"match_confidence": "verified",
"source_url": "https://boards-api.greenhouse.io/v1/boards/stripe/jobs?content=true",
"scraped_at": "2026-10-08T19:43:40.581Z"
}

record_key is ats:slug:job_id and is unique across the run, so you can upsert on it and spot closed roles between runs. workplace_type is one of remote, hybrid, onsite or unknown, and is_remote is always a boolean.

A resolution record

From the same run.

{
"type": "resolution",
"company_input": "stripe.com",
"company": "Stripe",
"status": "resolved",
"ats": "greenhouse",
"ats_slug": "stripe",
"jobs_found": 728,
"jobs_returned": 25,
"reason": "Resolved to Greenhouse with 728 open job(s), 25 returned.",
"probes_attempted": 1,
"candidate_slugs": ["stripe"],
"candidates_tried": ["greenhouse:stripe"],
"discovered_via": null,
"match_confidence": "verified",
"weak_candidate": null,
"source_url": "https://boards-api.greenhouse.io/v1/boards/stripe/jobs?content=true",
"scraped_at": "2026-10-08T19:43:40.581Z"
}

And a company whose guessed board belonged to someone else, from a resolve run the same day. The board was found, checked, rejected and not charged:

{
"type": "resolution",
"company_input": "bbc.co.uk",
"status": "not_found",
"ats": null,
"reason": "No public job board found on greenhouse, lever, ashby, workable, smartrecruiters, recruitee for slug(s) bbc, and the careers page carried no board link. A Recruitee board \"bbc\" answered but was not used: its job links point to careers.bbc.be, a different site from bbc.co.uk. If it is the right board, force it with recruitee:bbc.",
"candidates_tried": ["greenhouse:bbc", "lever:bbc", "ashby:bbc", "workable:bbc", "smartrecruiters:bbc", "recruitee:bbc"],
"match_confidence": null
}

status is one of:

StatusMeaning
resolvedA live board with at least one open job was found.
board_found_emptyAn account exists but lists no jobs. When it was only guessed, ats stays null and the account is given in weak_candidate, because an empty account does not show the company uses that system.
not_foundNo board answered on any of the six systems and the careers page carried no board link. A board that answered but points to another company is named in the reason.
input_errorThe entry or the run input was not usable. The reason says why.

match_confidence says how sure the match is: verified (the board's job links are on the company's domain, or its careers page links to the board), name_match (the board's published company name fits), guessed (only the slug matched; Lever and Ashby publish no company name to check) or override (you named the board).

Use it from Claude, Cursor or any MCP client

Add this Actor to any MCP client as a single tool through the Apify MCP server:

https://mcp.apify.com?tools=omargnagy/ats-jobs-by-domain
  • Claude.ai and Claude Desktop: add a custom connector with that URL and sign in with your Apify account.
  • VS Code: add it as an HTTP MCP server with that URL; it signs in to Apify the same way.
  • Claude Code: claude mcp add --transport http ats-jobs "https://mcp.apify.com?tools=omargnagy/ats-jobs-by-domain" --header "Authorization: Bearer <APIFY_TOKEN>"
  • Cursor and other clients: use the URL with an Authorization: Bearer <APIFY_TOKEN> header.

Then ask in plain language, for example: "Which of stripe.com, n8n.io and gitlab.com have open data engineering roles in Europe?" The agent calls this Actor and reads the job records. Runs started this way are billed at the same per-event prices below.

Run it from the API, a schedule or an integration

Call it like any Apify Actor. This returns the records in one request:

curl -X POST "https://api.apify.com/v2/acts/omargnagy~ats-jobs-by-domain/run-sync-get-dataset-items" \
-H "Authorization: Bearer $APIFY_TOKEN" -H "Content-Type: application/json" \
-d '{"mode":"jobs","companies":["stripe.com","posthog.com"],"maxJobsPerCompany":10,"includeDescription":false}'

Schedule it daily on Apify to watch a list of companies, send results on with a webhook, or connect it to Make, Zapier or n8n through Apify's integrations.

Pricing

Pay per event, no start fee. From $0.002 per job and $0.01 per resolved board, lower on Bronze, Silver and Gold plans.

EventPriceCharged when
jobfrom $0.002Once per job record delivered to you.
resolutionfrom $0.01Once per distinct ATS board per run. In jobs mode, only when at least one of that board's jobs was delivered. In resolve mode, once per resolved board.

Not charged: a company that resolves to nothing, an empty board, a board where no job matched your role filters, a slug-only guess on a country domain or a very short name (match_confidence: "guessed", the reason says so), input_error records, and duplicates suppressed inside a run.

What a run costs at the base price:

  • The prefilled example (3 companies, up to 25 jobs each): 60 jobs and 3 boards, $0.15.
  • 20 companies at up to 30 jobs each: 406 jobs and 19 boards, about $1.00 (measured on 8 October 2026).
  • resolve mode on 100 companies of which 60 resolve: $0.60 (calculated).

Set a maximum cost and it is respected. If you set a maximum cost per run, the run delivers only what that amount covers, then stops with a status message such as "Stopped at your maximum cost: 5 job(s) delivered from the first 1 of 25 companies". Nothing past the limit is written. Records are charged as they are delivered, one company at a time, and the OUTPUT record carries the real delivered and charged counts.

Limits

  • Six systems. Greenhouse, Lever, Ashby, Workable, SmartRecruiters and Recruitee. A company on Workday, Taleo, SuccessFactors, iCIMS, BambooHR, Personio or a hand built careers page comes back as not_found, or as board_found_empty with ats left empty when a dormant account on one of the six shares its name.
  • 500 companies per run, processed in batches of 20 with 4 at a time. The first 100 run unless you raise maxCompanies.
  • Two companies with the same name can collide. name_match means the board's published name equals the company's, and an unrelated company can share it: gong.io matched a SmartRecruiters board named "GONG!" that belongs to a New York media startup. guessed means only the slug matched. When it matters, check match_confidence and company, or name the board with ats:slug.
  • No salary data. Salary and compensation fields are not returned.
  • Careers-page discovery reads served HTML only, from /careers and the homepage, and only after guessing failed. A board link injected by JavaScript is not seen. It reads at most 400 KB per page with an 8 second timeout and honours each site's robots.txt.
  • An empty Ashby answer is ambiguous. Ashby answers {"jobs":[]} both for a board with no openings and for a company that has not switched the public API on, so those come back as board_found_empty with that caveat in the reason.
  • employment_type is always null for Greenhouse, which does not publish it. The other five do.
  • company falls back to the board slug for Lever and Ashby, which publish no company display name.
  • updated_at comes only from Greenhouse and Recruitee. The others publish a posting date only.
  • Location parsing is conservative. A multi-location string such as SF, NYC, SEA keeps location_raw and leaves city null rather than guessing.
  • resolve mode ignores the role filters, so its jobs_found is always the board's full total.
  • Every run reads the boards fresh. Job postings are public data the companies publish themselves; respect each vendor's terms and applicable law in how you store and use them.

What it does not do

It does not scrape LinkedIn, Indeed, Glassdoor or any job aggregator, it does not render pages in a browser or bypass bot protection, it does not touch applicant data or anything behind a login, and it does not apply to jobs for you.

FAQ

Does it need a proxy? No. Every job endpoint it calls is a public, documented, no-auth JSON endpoint served by the ATS vendor.

How do I find out which ATS a company uses without pulling its jobs? Run mode: "resolve". It reports the ATS, the slug, the match confidence and the open job count, and fetches no job records.

Why did my company come back as board_found_empty or not_found? Read the reason and candidates_tried. Either the company uses a system this Actor does not cover, its slug is unusual, or its board is empty. If you know the board, pass it as ats:slug.

Does it return salaries? No. Only the fields shown in the job record above.

Does it cover Workday? No. It covers Greenhouse, Lever, Ashby, Workable, SmartRecruiters and Recruitee.

Can I track new roles over time? Yes. Schedule the same input daily and compare record_key values between runs: new keys are new roles, missing keys are closed ones.

What happens to a list of 400 companies? Set maxCompanies to 400 or more and it runs. Results are written company by company and every entry gets its own resolution record.

How much does a typical run cost? About $0.05 per company that has 20 matching jobs at the base price, plus nothing for companies that do not resolve. See Pricing for measured examples.