Back to News & Insights
JavaScript August 29, 2026 · 4 min read

How to Find Companies That Just Started Hiring (Greenhouse, Lever & Ashby APIs)

When a company posts a job, that posting comes with a timestamp, and the timestamp is the interesting...

How to Find Companies That Just Started Hiring (Greenhouse, Lever & Ashby APIs)

When a company posts a job, that posting comes with a timestamp, and the timestamp is the interesting part. A new "VP of Sales" role usually means budget just got approved and a decision-maker seat is about to be filled. A first "Data Engineer" opening means someone is standing up a data platform right now. Three "Account Executive" listings in one week means a team is scaling its go-to-market this quarter.

People call this hiring intent data, and it's one of the more useful buying signals around because it's timed. A role that shows up today is a window that's open today. Six weeks later the tool has been picked and the problem is quietly solved.

You don't need an expensive intent-data subscription to see it. Three of the biggest applicant tracking systems (Greenhouse, Lever, and Ashby) serve their customers' job boards as public, unauthenticated JSON. If you can make an HTTP request, you can build your own "who's hiring" feed. This post covers how to pull the data, and then the part people usually get wrong, which is working out what's actually new.

The careers page on a company's site is usually just a front end for a JSON feed the ATS serves publicly. No key, no OAuth. You just need the company's board slug.

You can usually find the slug by looking at a company's "Careers" link (boards.greenhouse.io/acme, jobs.lever.co/acme, jobs.ashbyhq.com/acme).

Here's a small Node script (built-in fetch, Node 18+) that hits a Greenhouse board and keeps only the roles matching a keyword list.

Lever and Ashby return slightly different shapes. Lever uses text and hostedUrl, and Ashby nests its postings under jobs. So you write one small normalizer per source that maps each into a common { id, title, location, url }. Once that's done, everything downstream works the same regardless of where the data came from.

This is where most homemade trackers break. These APIs give you a current snapshot, meaning the roles that are open right now. What they don't give you is a reliable "posted at" field you can trust across all three providers. Greenhouse especially has no dependable creation date on the board endpoint, and updated_at changes every time someone edits a description.

So if you want new postings, which is the actual signal, you have to work out the difference yourself. You store what you saw last time and compare it against this run.

Persist the state somewhere durable, even if it's just a set of job IDs per company. Lose it, and the next run treats every open role as new and floods you with false positives.

Key off the provider's job ID, not the title. Titles get edited, and a renamed role shouldn't show up as new.

The first run is a cold start. You have no history yet, so seed the state and expect everything to look new that one time.

Normalize before you diff. If you compare raw responses from three different APIs, your logic turns into a pile of special cases.

Watch for roles that disappear, too. A req that drops off usually means it was filled, which is its own useful signal.

Once you have a clean feed of new roles, the uses are fairly obvious. You can watch a list of target accounts and get pinged the moment a relevant role opens. You can rank by seniority, since a "VP" opening in your buyer's department is a stronger, budget-backed trigger than a backfill. Or you can spot scaling motions, like three new AE reqs in a week from a company that's clearly investing in sales.

It holds up at scale too. I recently ran this across ten companies at once (Stripe, OpenAI, GitLab, Anthropic, Databricks, Coinbase, Airbnb, Discord, Ramp, and Notion) and pulled 3,664 normalized job postings across all three ATS platforms in about a second, each tagged as new, updated, or removed against the previous run. The data is right there in public JSON. The real work is the normalizing and the change-detection state.

All of this is doable in an afternoon. Keeping it running is the annoying part: the change-detection state, the per-provider normalizing, the scheduling, the retries when a board throws a 404. That's the stuff that eats weekends.

If you'd rather skip it, I packaged this same approach as an Apify actor that watches Greenhouse, Lever, and Ashby boards for a list of companies and returns only the new roles run over run: ATS Job Scraper for Greenhouse, Lever & Ashby. You give it your target accounts, turn on monitor mode, and put it on a schedule.

Want to discuss this further?

Book a free strategy call with our team to see how these insights apply to your specific business goals.

Book a consultation