SiteVerdict Job Postings API: Greenhouse, Lever, Ashby +3 avatar

SiteVerdict Job Postings API: Greenhouse, Lever, Ashby +3

Pricing

Pay per event

Go to Apify Store
SiteVerdict Job Postings API: Greenhouse, Lever, Ashby +3

SiteVerdict Job Postings API: Greenhouse, Lever, Ashby +3

Get every open job from company careers boards on Greenhouse, Lever, Ashby, Workable, SmartRecruiters and Recruitee via their official public APIs. One clean schema: salary, remote, parsed locations. Auto-detect boards from careers URLs. Monitor new, changed and closed jobs.

Pricing

Pay per event

Rating

0.0

(0)

Developer

Aman Thakran

Aman Thakran

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

9 days ago

Last modified

Categories

Share

Company Job Postings API: Greenhouse, Lever, Ashby, Workable, SmartRecruiters & Recruitee

Every open job from the companies you care about, in one clean schema, straight from the official public job-board APIs their careers pages use. Paste careers URLs or company domains. You get title, team, parsed locations, remote/hybrid/on-site, employment type, salary (when published), dates, apply links and descriptions. Run it on a schedule and get only the new, changed and closed jobs.

By SiteVerdict (BharatFare Travel and Technologies Ltd, UK).

  • 6 ATS platforms, 1 schema. No more writing a separate parser for each vendor.
  • Auto-detect. Paste any board URL, an identifier like greenhouse:airbnb, or just stripe.com. The Actor finds the board.
  • Salary you can trust. Structured pay ranges (Ashby, Lever, Recruitee, Greenhouse pay transparency) are used first. Otherwise ranges are parsed from pay-transparency text and always flagged salary_source: "parsed_text".
  • Monitoring built in. Labels every job NEW / CHANGED (with the fields that changed) / CLOSED, compared with your previous run.
  • Robust. One failing board never stops the run. Retries with backoff, per-vendor rate limiting, timeouts and a per-board status report.
  • Fair pay-per-event pricing. You pay per job delivered plus a tiny fee per board checked. Failed boards are never charged, and your max-charge limit is always respected.

Which ATS platforms are covered?

ATSWhat you can pasteOfficial public endpoint usedStructured salaryWorkplace typeDescription
Greenhouseboards.greenhouse.io/acme, job-boards.greenhouse.io/acme, embed ?for=acme, greenhouse:acmeJob Board API boards-api.greenhouse.io/v1/boards/{token}/jobs?content=truePay-transparency ranges (optional, 1 request per job) and currency custom fields. Otherwise parsed from textCustom field when published, else detectedHTML + text
Leverjobs.lever.co/acme, jobs.eu.lever.co/acme, lever:acme, lever-eu:acmePostings API api.lever.co/v0/postings/{company}?mode=json (EU: api.eu.lever.co)salaryRange when publishedYesHTML + text (lists and additional sections included)
Ashbyjobs.ashbyhq.com/acme, ashby:acmePublic Job Posting API api.ashbyhq.com/posting-api/job-board/{org}?includeCompensation=trueYes (compensation tiers)YesHTML + text
Workableapply.workable.com/acme, acme.workable.com, workable:acmePublic jobs widget API apply.workable.com/api/v1/widget/accounts/{subdomain}?details=trueParsed from textRemote flagHTML + text
SmartRecruiterscareers.smartrecruiters.com/Acme, jobs.smartrecruiters.com/Acme, smartrecruiters:AcmePosting API api.smartrecruiters.com/v1/companies/{id}/postings (+ /postings/{id} for descriptions)Parsed from textYes (remote/hybrid)HTML + text
Recruiteeacme.recruitee.com, recruitee:acmeCareers Site API {company}.recruitee.com/api/offers/Yes (salary min/max/period)Yes (remote/hybrid/on-site)HTML + text

Careers pages on a company's own website (for example https://www.notion.com/careers) are scanned for links, iframes and embed scripts from these vendors.

Quick start

1. Get all jobs from a few boards

{
"boards": [
"greenhouse:discord",
"https://jobs.lever.co/spotify",
"https://jobs.ashbyhq.com/linear",
"https://apply.workable.com/huggingface/",
"https://channable.recruitee.com"
]
}

2. Find the board from a company domain

{ "discoverDomains": ["stripe.com", "figma.com", "ramp.com"] }

The Actor reads the homepage and a few careers pages (it respects robots.txt) and finds the ATS link. If there is none, it can try the domain name as a board slug on each ATS's public API (probeAtsApis). Where the vendor publishes a company name, it must match the domain. Each board's detected_by field in the SUMMARY record shows how it was found.

3. Remote engineering jobs posted this week, with salaries

{
"boards": ["greenhouse:stripe", "ashby:openai", "ashby:ramp"],
"keywords": ["engineer*", "developer"],
"keywordScope": "title",
"workplaceTypes": ["remote"],
"postedWithinDays": 7,
"onlyWithSalary": true,
"descriptionFormat": "none"
}

4. Daily monitor: only new, changed and closed jobs

{
"boards": ["greenhouse:airbnb", "lever:spotify", "smartrecruiters:ServiceNow"],
"monitorMode": true,
"monitorOutput": "changes",
"monitorStateKey": "competitor-hiring"
}

Schedule it daily in Apify. The first run outputs every job as NEW (or set emitBaselineOnFirstRun: false to only save a baseline). Later runs output only NEW, CHANGED (with changed_fields) and CLOSED rows. A quiet day costs just the per-board fee.

Filters

All filters are optional. Different filters combine with AND, and values inside one filter combine with OR.

FilterExampleNotes
keywords["data engineer", "ml*"]Whole word or phrase, case-insensitive, * wildcard. Searches title + department + description (or title only with keywordScope: "title")
excludeKeywords["intern", "principal"]Matched against the title
departments["Engineering", "Sales"]Matches department or team (substring)
locations["London", "Germany", "CA", "remote"]City, region, country name or 2-letter country code. remote = fully remote jobs
workplaceTypes["remote", "hybrid"]Jobs with an unknown workplace type are excluded when this is set
employmentTypes["full_time", "contract"]Normalised types
postedWithinDays14Uses the first-published date (falls back to last-updated)
onlyWithSalarytrueStructured or parsed salary
maxJobsPerCompany / maxJobsTotal50 / 1000Newest first

Output

One dataset row per job. All six ATSs map to the same fields:

FieldDescription
company, ats, board_token, job_id, job_keyjob_key = ats:board:job_id, stable across runs (use it to dedupe)
title, department, teamAs published (team = Lever team, Ashby team, Workable function, SmartRecruiters function)
locationThe location string as published
city, region, country, country_codeParsed primary location (ISO 3166-1 alpha-2 code)
locations[]Every location, each parsed into city / region / country
remote, workplace_typeremote / hybrid / onsite / null. remote is true only for fully remote roles
employment_type, employment_type_rawfull_time, part_time, contract, temporary, internship, volunteer, other, plus the vendor's label
salary_min, salary_max, salary_currency, salary_period, salary_source, salary_textsalary_source = structured (vendor field) or parsed_text (extracted from the description; salary_text shows the snippet)
posted_at, updated_atISO 8601 UTC, when the ATS publishes them
job_url, apply_urlPublic job page and application link
requisition_id, languageWhen published
description_html, description_textControlled by descriptionFormat
change_status, changed_fields, first_seen_at, closed_detected_atMonitoring mode only
contactsOnly when includeContacts is on (see below)

Example row (trimmed):

{
"company": "Discord",
"ats": "greenhouse",
"job_id": "8811881002",
"job_key": "greenhouse:discord:8811881002",
"title": "Senior Engineering Manager, Nitro",
"location": "San Francisco Bay Area",
"city": "San Francisco Bay Area",
"country_code": "US",
"salary_min": 304000,
"salary_max": 380000,
"salary_currency": "USD",
"salary_period": "year",
"salary_source": "parsed_text",
"salary_text": "The US base salary range for this full-time position is $304,000 - $380,000 + equity + benefits.",
"posted_at": "2026-10-09T20:09:30.000Z",
"job_url": "https://job-boards.greenhouse.io/discord/jobs/8811881002"
}

The dataset has four views: Overview, Salary, Remote & location and Changes. Each run also saves a SUMMARY record in the key-value store. It lists every board with its status (ok, not_found, error, skipped_*), job counts, timing and the error message if there was one, plus discovery results and inputs that could not be resolved.

Pricing (pay per event)

EventWhen it is charged
job-postingEach job row delivered to your dataset (including CLOSED rows in monitoring mode)
board-checkedEach company board fetched successfully (a small fee, so scheduled monitors with no changes stay cheap)

You are never charged for boards that fail or don't exist, for discovery pages, or for retries. The run stops cleanly when your Max total charge is reached, and the Actor never starts a board it cannot afford to deliver at least one job from. See the Store pricing tab for current prices.

Performance

Measured on real public boards (11 Oct 2026, 1 GB memory):

RunResult
5 sample boards (Greenhouse, Lever, Ashby, Workable, Recruitee) + SmartRecruiters167 jobs in ~9 s
Stripe (729) + OpenAI on Ashby (815) + Experian on SmartRecruiters (393, with descriptions)1,937 jobs in 63 s, peak about 410 MB
Domain discovery for 6 sites~6 s

Greenhouse, Lever, Ashby, Workable and Recruitee return a whole board in one request. SmartRecruiters needs one extra request per job to get the description, so large SmartRecruiters boards take longer. For those, use descriptionFormat: "none" or title-only keywords.

  • Official public endpoints only. Every request goes to an endpoint the ATS vendor documents for publishing a company's jobs on its careers site (Greenhouse Job Board API, Lever Postings API, Ashby Job Posting API, Workable jobs widget, SmartRecruiters Posting API, Recruitee Careers Site API). No login, no API keys, no CAPTCHA solving, no proxies, no bypassing of any access control.
  • Honest identity and polite rate. A clear user agent (SiteVerdict-JobPostings/…), conservative per-vendor rate limits, and Retry-After is always honoured.
  • Company websites: discovery fetches only a handful of pages per domain and follows robots.txt.
  • No job-board scraping. This Actor does not touch LinkedIn, Indeed, Glassdoor or any aggregator.
  • Job data, not people. The output is the job advert the company chose to publish. includeContacts is off by default. When you turn it on, you only get contact details the company itself published on the posting (a SmartRecruiters posting creator's name, a Recruitee application mailbox). Turn it on only if you have a lawful basis under GDPR / UK GDPR, and respect each vendor's terms.
  • You are responsible for how you use the data (for example, respect each company's copyright in its job descriptions when republishing them).
  • Licence of the data: job adverts belong to the companies that publish them and are provided under each ATS vendor's own terms (Greenhouse, Lever, Ashby, Workable, SmartRecruiters, Recruitee). No licence to republish is granted by this Actor.
  • Where results are stored: the default dataset and key-value store of the run, inside your own Apify account. These default storages are unnamed. How long Apify keeps them is set by Apify and your plan, not by SiteVerdict (Apify data retention); you can delete them sooner in Apify Console.
  • Monitoring (off by default): to detect NEW / CHANGED / CLOSED jobs, each job's ID, title, URL, location, department, posting date and short hashes of its fields are kept in a named key-value store in your account (siteverdict-job-postings-state, or the name you set). Apify keeps named stores until you delete them.
  • What SiteVerdict keeps: nothing. The Actor runs in your Apify account and sends no data to SiteVerdict.

FAQ

I only know the company name. Put its website in discoverDomains. If you know the ATS, ats:slug (for example lever:spotify) is the fastest.

SmartRecruiters says "not found" but the company uses SmartRecruiters. SmartRecruiters identifiers are case-sensitive and sometimes differ from the brand (for example Ubisoft2). Copy the identifier from the company's careers.smartrecruiters.com/... URL.

Why is salary_min empty? The company didn't publish pay for that role. Ashby, Recruitee and many US Greenhouse/Lever boards do publish it. Turn on greenhousePayTransparency to read Greenhouse's structured pay ranges where they exist.

Is a parsed salary reliable? It is taken from the company's own pay-transparency sentence, and salary_text shows the exact snippet. The parser needs a currency, ignores funding/revenue/perk amounts, and accepts a single amount only next to salary words. It is still a parse, which is why it is flagged.

How does CHANGED work? For each job we store short hashes of title, department, team, locations, workplace, employment type, salary, description, apply URL and requisition ID. changed_fields lists the hashes that differ. Changing your filters starts a fresh baseline automatically, so a filter change is never reported as closures.

Can a failed fetch make all jobs look CLOSED? No. Closures are only reported for boards fetched successfully and completely: not after errors, not when maxJobsPerCompany truncated the list, and not when the charge limit cut the output short.

Workday, iCIMS, Taleo, Personio, Teamtailor? Not yet. Ask for the ATS you need.

Known limits

  • Location parsing is rules-based (ICU country names plus aliases and local names, US/CA/AU states and provinces, a list of major cities). Ambiguous strings keep the original text in location; multi-city strings separated only by commas may be split imperfectly.
  • Lever and Ashby publish no company name. The board slug is used, prettified (openai becomes Openai).
  • Greenhouse EU-hosted board URLs (job-boards.eu.greenhouse.io/...) are queried through the main Job Board API (boards-api.greenhouse.io); if a board is not served there it is reported as not_found in SUMMARY.
  • Workable's widget API rate-limits aggressively, so Workable boards are fetched at most once every 1.5 s.

Support

Open an issue on the Actor's Issues tab.