Job Postings Scraper API : $1 per 1,000 Jobs avatar

Job Postings Scraper API : $1 per 1,000 Jobs

Pricing

from $1.00 / 1,000 job posting returneds

Go to Apify Store
Job Postings Scraper API : $1 per 1,000 Jobs

Job Postings Scraper API : $1 per 1,000 Jobs

Fetch every live job posting from any company's career board (Greenhouse, Lever, Ashby, Workable) as clean, normalized JSON: real-time, not from a stale index.

Pricing

from $1.00 / 1,000 job posting returneds

Rating

0.0

(0)

Developer

Workware

Workware

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

19 hours ago

Last modified

Share

Job Postings API: All Jobs at Any Company

Give it a company: get every live job on that company's official career board as clean, normalized JSON, in seconds, straight from the ATS. Not from an index that was built a few hours ago: this Actor reads the employer's own Greenhouse, Lever, Ashby, or Workable board at the moment you ask, so what you get back is what a candidate would see on the careers page right now.

  • What you put in: a list of companies, each given as a name, a website domain, or a board URL. Up to 500 per run, looked up one after another.
  • What you get back: one record per live job posting, in a single canonical schema no matter which ATS it came from, plus one status record per company telling you exactly what happened to it.
  • Why this one: the alternatives sell you a pre-built index with an indexing delay and a per-run job cap. An index cannot answer "what is on company X's board right now". This can, and it is roughly four times cheaper per job.
  • Boosted by the Apify platform: full REST API access, scheduling, monitoring, webhooks and integrations, proxy rotation, and dataset export to JSON, CSV, or Excel.

What is the Job Postings API and what can it do?

The Job Postings API is a company-first jobs API: you ask about employers, not about keywords. Point it at a company and it works out which applicant tracking system that company uses, reads the public board, and returns every open role on it as structured JSON. It is the tool you want when you already know whose jobs you care about (the accounts in your CRM, the portfolio companies in your fund, the competitors you track) and you want their current openings on demand or on a schedule.

Supported applicant tracking systems: Greenhouse, Lever, Ashby, and Workable. Together these cover a large share of software, fintech, biotech, and growth-stage employers worldwide, including Lever's EU-hosted cluster. Every one of them is read through its official, public, no-authentication JSON API: the most stable class of source that exists for jobs data, and the reason this Actor needs no browser, no residential proxy, and no anti-bot workarounds.

What it deliberately does not do: it does not search across companies by keyword, it does not maintain an index or a history, and it does not enrich postings with AI-inferred salaries, skills, or taxonomies. Those are separate concerns, and inferred fields are exactly where indexed competitors accumulate quiet errors. This Actor's promise is narrower and testable: the live board, correctly normalized, honestly labelled.

How a company gets resolved, in order: if you supply a board URL, it is used directly. Otherwise the Actor reads the company's own careers page and looks for a board link: evidence straight from the employer. If that finds nothing, it probes each ATS with candidate slugs derived from the name and domain, and a similarity guard rejects near-misses so acme never resolves to acme-health. If every step misses, you get a definitive no_board answer, which is a real result: some employers genuinely have no public board.

What data does it extract? (output fields)

Every record is a canonical JobPosting: a stable id, the source and its native id, the posting URL and apply URL, raw and normalized titles, company, structured location, department, employment type, salary, description in HTML and plain text, and the dates the role was posted and observed.

Two fields deserve a note because they are where jobs data usually goes wrong:

  • salary carries a source label: stated only when the employer set a structured salary the ATS returns as data (Ashby compensation, Lever salaryRange), and parsed when it was read out of a description. If a role's pay cannot be established honestly, the field is absent. It is never guessed.
  • location.remoteScope is the geography a remote candidate must be eligible to work in: ISO country codes and macro-region labels such as ["US","CA"] or ["EU"], populated when the employer states a restriction and absent when they state none. Absent means unstated, never "worldwide".

Source-specific fields that do not fit the canonical schema (Greenhouse offices and departments, Ashby compensation tiers) are preserved under extras.<source> rather than dropped or forced into a field where they do not belong. Personal contact details are dropped at a single normalization chokepoint and never reach the dataset.

Alongside the job records, each company produces one company-status row:

{ company, resolvedSource, boardToken, jobCount, status }
, where status is found, no_board, or error. This is what makes an empty result unambiguous: you always know whether a company has no jobs, no board, or simply could not be reached.

FieldTypeAlways presentDescription
idstringAlwaysStable id: sha1(source + sourceId) (computed by normalizers/actors, not here).
sourcegreenhouse | lever | ashby | workable | wellfound | seek | stepstone | dice | ziprecruiter | bayt | xing | reedAlwaysThis Actor reads Greenhouse, Lever, Ashby and Workable; the other values are reserved for sibling Actors.
sourceIdstringAlwaysNative id at the source.
urlstringAlwaysCanonical public posting URL.
applyUrlstringOptionalDirect apply link when distinct from url.
titlestringAlwaysRaw title as posted.
titleNormalizedstringAlwaysCleaned title (no req-ids, no ALL CAPS, trimmed seniority tags): normalized in M1b.
company.namestringAlwaysDisplay name.
company.websitestringOptionalCompany website when known.
company.sourceSlugstringAlwaysSource-native company slug/identifier.
location.rawstringAlwaysRaw location string as provided by the source.
location.citystringOptional
location.regionstringOptional
location.countrystringOptionalISO-3166 country code when resolvable.
location.remotefull | hybrid | onsite | unknownAlwaysRemote-work posture; unknown when it cannot be determined.
location.remoteScopestring[]OptionalFor remote roles: the geography a remote candidate must be eligible to work in (visa / right-to-work), e.g. ['US','CA'], ['EU'], ['GLOBAL']. Values are ISO-3166-1 alpha-2 country codes and/or canonical macro-region labels (GLOBAL|EU|EMEA|APAC|LATAM|MENA|ANZ|DACH| AMERICAS|NORAM). Absent when the source states no restriction: never assumed global.
departmentstringOptionalSource-provided team/department.
employmentTypefull_time | part_time | contract | intern | temporary | unknownOptional
salary.rawstringOptionalOriginal salary display string when present.
salary.minnumberOptional
salary.maxnumberOptional
salary.currencystringOptionalISO-4217 currency code when known.
salary.periodyear | month | day | hourOptional
salary.sourcestated | parsedOptional
descriptionHtmlstringOptionalSanitized HTML description when available.
descriptionTextstringAlwaysPlain-text description.
postedAtstringOptionalWhen the role was published at the source (not scrape time).
firstSeenAtstringAlwaysOur observation window. In live-fetch actors both are simply the run's scrape time: do NOT build cross-run observation tracking here; that is new-job-postings-api's (#18) concern.
lastSeenAtstringAlways
extrasobjectOptionalSource-specific fields, namespaced under extras.<source>.*; never breaks the schema.

How to use the Job Postings API (tutorial)

  1. Click Start with the example input already filled in: one company, no options.
  2. Watch the run finish (a single company typically completes in a few seconds).
  3. Open the Dataset tab. You will see the job records plus one company-status row.
  4. Export as JSON, CSV, or Excel, or call the run from your own code through the Apify API.

To run it on your own list, replace the companies array. Each entry needs at least one of name, domain, or atsUrl; supplying domain resolves most reliably, and supplying atsUrl skips detection entirely and is the fastest path if you already know the board.

Companies in a batch are processed one after another, at a deliberately polite request rate to the ATSs: a single company typically takes a few seconds, and a long list takes roughly that per company. If you are polling on a schedule, prefer several small runs over one very large one.

How much does it cost?

Pay-per-event, with two events:

  • $0.005 per company processed: charged once per company that reached a definitive answer, whether that answer is "here is the board" or "this company has no public board". The detection work has value either way.
  • $0.001 per job posting returned: charged per validated record.

Failed lookups are free. A company whose status is error is never charged, and neither are the records of a company whose fetch failed part-way through: they are discarded rather than delivered. We charge for answers, not for our own failures.

A worked example: 100 companies averaging 40 open roles each costs

100 × $0.005 + 4,000 × $0.001 = $4.50
. The comparable indexed API charges $4.00 per 1,000 jobs, which would be $16.00 for the same 4,000 postings. Platform usage costs are absorbed, not passed through.

EventWhat it isCharged forPrice
company-processedCompany processed (definitive answer)each run$5.00 / 1,000
job-resultJob posting returnedeach record delivered$1.00 / 1,000

Input and output examples

Input: the simplest useful run:

{ "companies": [{ "name": "Anthropic" }] }

Input: a filtered batch:

{
"companies": [
{ "domain": "stripe.com" },
{ "atsUrl": "https://jobs.ashbyhq.com/ramp" }
],
"titleFilter": "engineer",
"remoteOnly": true,
"maxJobsPerCompany": 25
}

Output: one job record (trimmed) and its company's status row:

{
"id": "8f2c…",
"source": "greenhouse",
"url": "https://job-boards.greenhouse.io/acme/jobs/4001",
"title": "Senior Backend Engineer",
"titleNormalized": "Senior Backend Engineer",
"company": { "name": "Acme", "sourceSlug": "acme" },
"location": { "raw": "Remote — US", "country": "US", "remote": "full", "remoteScope": ["US"] },
"employmentType": "full_time",
"salary": { "min": 180000, "max": 220000, "currency": "USD", "period": "year", "source": "parsed" },
"postedAt": "2026-06-20T10:00:00Z"
}
{ "type": "company-status", "company": { "domain": "acme.com" }, "resolvedSource": "greenhouse",
"boardToken": "acme", "jobCount": 42, "status": "found" }

titleFilter is a plain, case-insensitive substring match, not a regular expression. remoteOnly keeps roles whose posture is remote or hybrid; it does not filter on eligibility geography, so a remote role restricted to one country is still returned and you can filter on location.remoteScope yourself.

FieldTypeRequiredDefaultDescription
companiesarrayYes-The companies to look up: one run handles the whole batch, one company at a time. Each entry needs at least one of name, domain, or atsUrl. domain resolves most reliably; atsUrl skips detection altogether.
includeDescriptionbooleanNotrueInclude the full job description in each record. Descriptions are always FETCHED (salary parsing and normalization read them): turning this off strips them from the output to keep datasets small.
remoteOnlybooleanNofalseReturn only roles whose remote posture is remote or hybrid. This filters the posture, not the eligibility geography: a remote role open only to US residents is still returned.
titleFilterstringNo-Keep only roles whose title contains this text, case-insensitively. Plain substring matching: not a regular expression.
maxJobsPerCompanyintegerNo0Caps the jobs returned per company. 0 means no cap: return the whole board.

Other Actors you might need

ActorUse it when
Greenhouse Jobs ScraperYou only care about Greenhouse and already have board tokens.
Ashby Jobs ScraperYou only care about Ashby boards.

If you do not know which ATS a company uses, or your list spans several of them, this Actor is the one you want: resolving the board is the part it does for you.

FAQ, legality, and support

How is this different from indexed job APIs?

An indexed API crawls many career sites on its own schedule and serves you a copy. That is the right shape for "show me every Python job posted this week", and the wrong shape for "what is on this company's board right now": the copy is as fresh as the last crawl, and crawls run hours apart. This Actor holds no index. It reads the employer's board when you ask, which means no indexing delay and no per-run cap on how much of a board you can retrieve.

Which applicant tracking systems are supported?

Greenhouse, Lever (including the EU cluster), Ashby, and Workable, all through their official public JSON APIs. If a company uses an ATS outside this list, you get a no_board status rather than a silent empty result.

What if a company has no public board?

You get a company-status row with status: "no_board", and that counts as a definitive answer. Many employers post only to their own bespoke careers page or to job boards rather than running a public ATS board; "this company has no public ATS board" is genuinely useful information, and it is priced as one processed company with no job results.

What happens when a source changes its API?

Every response is shape-checked before it is normalized. A change that breaks the shape fails the affected company loudly instead of emitting silently wrong records, and a scheduled smoke test runs against known-stable boards so we usually find out before you do.

The data is public, employer-published job advertising, retrieved through the ATS vendors' own public APIs. Job postings are not personal data, attribution and apply URLs are preserved on every record, and recruiter and contact details are dropped rather than collected. As always, how you use the data is your responsibility.

Can I get a custom variant?

Yes: open an issue on the Actor or contact us through the Apify platform. Cross-company keyword search, per-posting detail enrichment, and new-jobs-only change tracking are all being built as separate Actors.