# Career Site Jobs API: Workday, Greenhouse, Lever, Ashby & more (`localwire/ats-jobs`) Actor

Every open job from company career sites on Workday, Greenhouse, Lever, Ashby, SmartRecruiters, SuccessFactors, Oracle, Workable, Recruitee, Personio and Pinpoint, in one schema. Give careers URLs, websites or company names; filter by keyword, country and remote; monitor mode returns only new jobs.

- **URL**: https://apify.com/localwire/ats-jobs.md
- **Developed by:** [Local Wire](https://apify.com/localwire) (community)
- **Categories:** Jobs, Business
- **Features:** Limited permissions
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$1.50 / 1,000 jobs

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## Career Site Jobs API: Workday, Greenhouse, Lever, Ashby, SmartRecruiters, SuccessFactors, Oracle, Workable, Recruitee, Personio & Pinpoint jobs

Get **every open job from a company's own careers site** as structured JSON for **$1.50 per 1,000 jobs** ($0.0015 per job, no start fee). This career site jobs API reads the public job-board endpoints of **Workday, Greenhouse, Lever, Ashby, SmartRecruiters, SAP SuccessFactors, Oracle Recruiting, Workable, Recruitee, Personio and Pinpoint**, the applicant tracking systems (ATS) behind most company career pages, and returns one consistent record per job.

Give it **careers-site URLs, company websites or just company names**. It finds the right job board, applies your filters, and in **monitor mode** returns only the jobs that are new since the last run, which is what hiring alerts and sales signals need.

It uses no browser, no proxies and no logins: only the endpoints and pages that the platforms' own career sites serve to every visitor, read at a polite pace.

### What you get

One record per job, in the same schema for all eleven platforms:

- **Identity:** a stable `id` (`platform:board:jobId`), the platform (`ats`, `atsName`), the company and its board id.
- **The role:** `title`, `department`, `team`, `employmentType` (normalised to full-time, part-time, contract, temporary, internship, apprenticeship or other) and the platform's own wording in `employmentTypeRaw`.
- **Where:** `location`, every location in `locations`, ISO country codes in `country` and `countries`, a `remote` flag and `workplaceType` (remote, hybrid or onsite) where the platform says.
- **Pay:** `salaryMin`, `salaryMax`, `salaryCurrency`, `salaryPeriod` and `salaryText`, where the employer publishes a range in the job board's structured fields.
- **The posting:** the full description as plain text (`descriptionText`), optionally as HTML, plus `jobUrl` and `applyUrl`.
- **Dates:** `postedAt` and `updatedAt` where the platform gives them, and `scrapedAt`.
- **Monitor fields:** `changeType` (`new` or `removed`) and `firstSeenAt` in monitor mode.

A full record from a Lever board looks like this:

```json
{
  "id": "lever:leverdemo:ad208490-4052-4f91-a57e-433f2d1e484b",
  "ats": "lever",
  "atsName": "Lever",
  "company": "Leverdemo",
  "companySlug": "leverdemo",
  "jobId": "ad208490-4052-4f91-a57e-433f2d1e484b",
  "title": "Customer Success Manager",
  "department": "Customer Success",
  "team": "Customer Success Team",
  "employmentType": "full-time",
  "employmentTypeRaw": "Regular Full Time (Salary)",
  "location": "Atlanta, Georgia",
  "locations": ["Atlanta, Georgia"],
  "country": "US",
  "countries": ["US"],
  "remote": false,
  "workplaceType": "hybrid",
  "salaryMin": 85000,
  "salaryMax": 175000,
  "salaryCurrency": "USD",
  "salaryPeriod": "year",
  "salaryText": null,
  "descriptionText": "Join a scaling, tight-knit team that’s working directly with innovative talent acquisition teams…",
  "descriptionHtml": null,
  "jobUrl": "https://jobs.lever.co/leverdemo/ad208490-4052-4f91-a57e-433f2d1e484b",
  "applyUrl": "https://jobs.lever.co/leverdemo/ad208490-4052-4f91-a57e-433f2d1e484b/apply",
  "postedAt": "2026-08-31T18:12:19.703Z",
  "updatedAt": null,
  "changeType": null,
  "firstSeenAt": null,
  "input": "https://jobs.lever.co/leverdemo",
  "detectedBy": "url",
  "scrapedAt": "2026-11-06T20:55:32.471Z"
}
```

- `id` is stable across runs, so you can de-duplicate or upsert.
- `country` and `countries` are ISO 3166-1 alpha-2 codes. Regions such as "Europe" or "North America" leave them empty.
- `input` is the `companies` entry that produced the job, and `detectedBy` says how its board was found: `url`, `explicit`, `website`, `guess` or `cache`.
- Descriptions are cut at 50,000 characters.

The dataset has three table views: **Overview**, **Salaries** and **Monitor changes**. The run's key-value store also gets an `OUTPUT` record that lists each company: the board found, how many jobs were listed, matched and returned, and any company that could not be found or read.

### Quick start

Only `companies` is required. This input returns up to 50 jobs from three job boards and costs at most $0.075:

```json
{
  "companies": ["https://job-boards.greenhouse.io/monzo", "https://jobs.ashbyhq.com/linear", "bunq.recruitee.com"],
  "maxJobsPerCompany": 20,
  "maxResults": 50
}
```

In Apify Console the form opens with these values already filled in, so you can press **Start** straight away. When you call the Actor from the API and leave the limits out, they default to 1,000 jobs per company and 5,000 jobs per run.

Engineering jobs in the UK and Ireland at three companies:

```json
{
  "companies": ["https://job-boards.greenhouse.io/monzo", "https://jobs.ashbyhq.com/linear", "bunq.recruitee.com"],
  "keywords": ["engineer", "developer"],
  "countries": ["GB", "IE"]
}
```

A daily alert of new remote roles at a list of target accounts:

```json
{
  "companies": ["Linear", "monzo.com", "https://jobs.lever.co/leverdemo"],
  "remoteOnly": true,
  "monitorMode": true,
  "monitorStoreName": "remote-watchlist"
}
```

Save the input as a **Task**, add a daily **Schedule**, and each run returns only the new jobs.

### Input reference

| Field | Type | Default | What it does |
|---|---|---|---|
| `companies` | list of text | required | Job-board or careers-site URLs, company websites, company names or `platform:board` entries. Up to 1,000 per run. |
| `keywords` | list of text | none | Keep jobs whose title, department or team contains ANY of these, matched at the start of a word and ignoring case and accents. |
| `searchDescriptions` | true/false | `false` | Also match `keywords` against the full description. |
| `excludeKeywords` | list of text | none | Drop jobs whose title contains ANY of these. |
| `countries` | list of text | none | Keep jobs in ANY of these countries. ISO codes or names: `GB`, `UK`, `Germany`, `United States`. |
| `locations` | list of text | none | Keep jobs whose location text contains ANY of these, e.g. `London`, `Remote`. |
| `remoteOnly` | true/false | `false` | Keep only jobs marked remote by the platform, or whose location says remote. |
| `departments` | list of text | none | Keep jobs whose department or team contains ANY of these. |
| `employmentTypes` | list | none | `full-time`, `part-time`, `contract`, `temporary`, `internship`, `apprenticeship`, `other`. Jobs with no published type are dropped when this is set. |
| `postedWithinDays` | number 1-365 | none | Keep jobs first published (or, failing that, last updated) in this many days. Jobs without a date are kept. |
| `postedSince` | date | none | Keep jobs posted on or after this date, e.g. `2026-11-01`. Overrides `postedWithinDays`. |
| `atsPlatforms` | list | all eleven | Which platforms to try when a company is given by name or website. URLs and `platform:board` entries always work. |
| `monitorMode` | true/false | `false` | Return only jobs that are new since the last run. |
| `emitRemoved` | true/false | `false` | In monitor mode, also return jobs that have disappeared (`changeType: "removed"`). |
| `monitorEmitExistingOnFirstRun` | true/false | `true` | On a monitor's first run, return the current jobs. Set to `false` to record them silently and pay nothing for the backlog. |
| `monitorStoreName` | text | `ats-jobs-monitor` | Name of the key-value store that holds the monitor's memory. Use one name per monitor. Letters, digits and hyphens. |
| `includeDescriptions` | true/false | `true` | Include the description as plain text. Turning it off makes runs faster on platforms that need one request per job. |
| `includeHtml` | true/false | `false` | Also include the description as HTML in `descriptionHtml`. |
| `maxJobsPerCompany` | number 1-10,000 | `1000` | Stop reading a company's board after this many matching jobs. |
| `maxResults` | number 1-100,000 | `5000` | Stop the run after this many jobs in total. |
| `useDetectionCache` | true/false | `true` | Remember the board found for a name or website for 30 days, in a key-value store called `ats-jobs-detection-cache` in your account. |

Invalid input fails at once with a message that lists every problem, so a person or an AI agent can fix it in one go.

### Supported platforms

| Platform | Board URL examples | `platform:board` form | Found from a company name? |
|---|---|---|---|
| Workday | `https://nvidia.wd5.myworkdayjobs.com/NVIDIAExternalCareerSite` | URL only | No, pass the URL |
| Greenhouse | `https://job-boards.greenhouse.io/monzo`, `https://boards.greenhouse.io/monzo` | `greenhouse:monzo` | Yes |
| Lever | `https://jobs.lever.co/leverdemo`, `https://jobs.eu.lever.co/acme` | `lever:leverdemo`, `lever-eu:acme` | Yes |
| Ashby | `https://jobs.ashbyhq.com/linear` | `ashby:linear` | Yes |
| SmartRecruiters | `https://jobs.smartrecruiters.com/BoschGroup` | `smartrecruiters:BoschGroup` | Yes |
| SAP SuccessFactors | the careers site itself, e.g. `https://careers.sap.com` | `successfactors:careers.sap.com` | No, pass the site |
| Oracle Recruiting | `https://<host>/hcmUI/CandidateExperience/en/sites/CX_1/requisitions` | URL only | No, pass the URL |
| Workable | `https://apply.workable.com/careers` | `workable:careers` | Yes |
| Recruitee | `https://bunq.recruitee.com` | `recruitee:bunq` | Yes |
| Personio | `https://1komma5grad.jobs.personio.de` | `personio:1komma5grad`, `personio-com:acme` | Yes |
| Pinpoint | `https://workwithus.pinpointhq.com` | `pinpoint:workwithus` | Yes |

A link to a single job on any of these boards works too: the Actor reads the board it belongs to.

### Jobs API by platform

What the Actor reads on each platform, and what that platform does and does not publish.

#### Workday jobs API

Workday career sites live at `<company>.wd1…wd12.myworkdayjobs.com/<Site>` or `myworkdaysite.com/recruiting/<company>/<Site>`. Each is a web app that loads its postings from JSON endpoints on the same host, without a login, and the Actor reads those endpoints. Paste any page of the site, with or without a locale such as `/en-US/`.

- The job list comes 20 postings a page and has no country and no real date, so the Actor reads each posting too (about 0.4 seconds each).
- Your `keywords` are sent to Workday's own search, so a keyword run on a 2,000-job site reads only the postings that can match.
- You get title, locations, the country from Workday's own country field, remote and hybrid flags where given, the time type as `employmentType`, the posting's start date as `postedAt`, the requisition id and the full description.
- Workday's public postings carry no department and no salary, so those fields stay empty.
- A company can have several sites (external, campus, internal). The Actor reads the one in the URL, up to 10,000 postings.

Only want Workday? [Workday Jobs API](https://apify.com/localwire/workday-jobs) is the same code with a Workday-first form, at the same price.

#### Greenhouse jobs API

Reads the official [Greenhouse Job Board API](https://developers.greenhouse.io/job-board.html): one request returns every published job on a board with its description. Accepts `job-boards.greenhouse.io/<board>`, `boards.greenhouse.io/<board>` and embedded board links.

- You get title, the first department, locations and offices, the description, and first-published and updated dates.
- Greenhouse has no remote field, so `remote` and `workplaceType` are read from the location text.
- The Job Board API does not include pay. A board in Greenhouse's EU data centre may not be readable through it.

#### Lever jobs API

Reads the official [Lever Postings API](https://github.com/lever/postings-api) for `jobs.lever.co/<site>`, and Lever's EU data centre for `jobs.eu.lever.co/<site>`. A board that is not on the US host is tried on the EU host automatically.

- One request returns the whole board, with department, team, commitment, every location, the workplace type and the description.
- Lever publishes a **salary range** where the employer filled it in: min, max, currency and interval.

#### Ashby jobs API

Reads the official [Ashby public job posting API](https://developers.ashbyhq.com/docs/public-job-posting-api) for `jobs.ashbyhq.com/<board>`, with compensation included.

- One request returns the whole board: department, team, employment type, primary and secondary locations with their countries, remote flag, workplace type, publish date and description.
- **Salary** comes from Ashby's compensation summary (salary first, hourly rates otherwise), with the published text in `salaryText`.
- Unlisted postings are skipped.

#### SmartRecruiters jobs API

Reads the official [SmartRecruiters Posting API](https://developers.smartrecruiters.com/docs/posting-api) for `jobs.smartrecruiters.com/<Company>`. Company ids are case-sensitive, so keep the case from the URL.

- The listing comes 100 postings a page with department, function, employment type, location, country and remote and hybrid flags.
- Descriptions need **one request per job**, made only for jobs that pass your filters. Turn `includeDescriptions` off on very large boards if you only need titles and locations.
- The Posting API does not include pay. The recruiter named on a posting is never copied.

#### SAP SuccessFactors jobs

SuccessFactors "Career Site Builder" sites run on the company's own domain, for example `careers.sap.com` or `jobs.compassgroupcareers.com`. They are plain HTML pages. Pass the careers site itself, or `successfactors:<host>`.

- The search results give the title, the link and usually the location. The job page, read once per job when descriptions are wanted, adds the company, date, department, employment type and description.
- Sites differ in layout, so fields are filled where the site shows them. These sites do not publish pay in a structured field.
- Your `keywords` are sent to the site's own search.
- When you give a company website rather than `successfactors:<host>`, the site's robots.txt is checked first, and a site that disallows its job search is not read.

#### Oracle Recruiting jobs API

Oracle Cloud HCM career sites have URLs like `https://<host>/hcmUI/CandidateExperience/en/sites/CX_1/requisitions`, on `oraclecloud.com` or on a company's own domain. The site is a web app over public REST resources, and the Actor reads those.

- The listing comes 25 jobs a page with title, posted date, primary and secondary locations, country, workplace type, schedule, category and job function.
- Descriptions need one request per job. Hiring-manager and contact fields in that record are never copied.
- Your `keywords` are sent to Oracle's own search. Pay is not included.

#### Workable jobs API

Reads the public jobs feed that Workable career pages use, for `apply.workable.com/<account>` or the older `<account>.workable.com`.

- One request lists the whole board with descriptions, department, function, employment type, location and a remote flag.
- With descriptions on, each job's own record is read as well, which adds the **salary range** and the workplace type (on-site, hybrid or remote).

#### Recruitee jobs API

Reads the official [Recruitee Careers Site API](https://docs.recruitee.com/reference/intro-to-careers-site-api) at `<company>.recruitee.com`.

- One request returns every published offer: department, employment type, locations with country codes, remote, hybrid and on-site flags, dates and description.
- **Salary** (min, max, currency, period) is included where the employer published it.
- The offer's application mailbox and its application questions are never copied.

#### Personio jobs API

Reads the official [Personio XML job feed](https://developer.personio.de/docs/retrieving-open-job-positions) at `<company>.jobs.personio.de` or `.com`.

- One request returns every open position: sub-company, department, recruiting category, employment type and schedule, office, date and description.
- **Salary** is included where published. The feed comes in the company's default language.

#### Pinpoint jobs API

Reads the public postings feed of `<account>.pinpointhq.com`.

- One request returns everything: department, division, employment type, workplace type, location and the description sections.
- **Compensation** (min, max, currency, frequency) is included when the employer has made it visible.
- Pinpoint publishes no posting dates, so `postedAt` is empty and date filters keep these jobs.

### Finding a company's job board

- **Most reliable:** paste the job-board URL (the page that lists the company's jobs) or use `platform:board`.
- **Website:** the Actor reads the site's robots.txt, then checks the page you gave plus `/careers` and `/jobs` for a link to one of the platforms. If the site is itself a SuccessFactors careers site, it is read directly. A site that refuses automated requests is not scanned; the Actor falls back to the next step.
- **Name:** the Actor tries likely board ids (for example "Monzo Bank Ltd" becomes `monzobank`, `monzo-bank`, `monzo`) on each platform where ids can be guessed, and takes the first board with open jobs. Different companies can share a name, so check `company` in the output, or pass the URL to be certain. Workday, Oracle and SuccessFactors boards cannot be guessed from a name.

A board found from a website or a name is remembered for 30 days, so later runs skip the search.

### Monitor mode: only new jobs

With `monitorMode` on, the Actor remembers each board's jobs in a key-value store in your account (named by `monitorStoreName`). Each run returns only jobs it has not returned before, and with `emitRemoved` also the jobs that have gone since the last run.

- Use **one monitor name per filter set**. If you change the filters, that monitor starts again.
- If a run stops early (a limit or your maximum cost), removals are not reported for that board, and jobs that were found but not returned are kept for the next run.
- To start a monitor without paying for the existing backlog, set `monitorEmitExistingOnFirstRun` to `false` for the first run.
- A rolling `postedWithinDays` window does not reset the monitor.

### Use cases

- **Hiring signals for sales and recruiting.** Track which target accounts are hiring, for which teams and where. A company opening five data-engineering roles is a buying signal.
- **New-job alerts.** Schedule a daily run in monitor mode and get only the roles posted since yesterday.
- **Job boards and aggregators.** Feed a niche board with direct-from-employer postings in one schema across eleven platforms.
- **Market and salary research.** Compare roles, locations, remote policies and published pay ranges across companies.
- **Competitor tracking.** Watch which teams your competitors are building, and with `emitRemoved` see when roles close.
- **AI agents.** A small, predictable JSON schema that an agent can call as a tool through Apify's MCP server.

### Pricing

**$0.0015 per job returned, which is $1.50 per 1,000 jobs.** There is no start fee and no monthly rental.

You pay for each record the Actor returns, including `removed` records in monitor mode. You pay nothing for jobs that your filters drop, for jobs a monitor has already returned, or for companies that cannot be found.

| What you run | Jobs returned | Cost |
|---|---|---|
| The pre-filled first run | 50 | $0.075 |
| Every job at one company with 600 openings | 600 | $0.90 |
| Engineering jobs at 200 companies | 2,000 | $3.00 |
| A one-off pull of 10,000 jobs | 10,000 | $15.00 |
| A daily monitor of 50 companies that finds 30 new jobs a day | about 900 a month | about $1.35 a month |

To cap spending, set **Max cost per run** in the run options, or lower `maxResults`. The Actor stops cleanly at the limit and says so in its status message.

### Use it from the API

Run the Actor and get the jobs back in one request:

```bash
curl -X POST "https://api.apify.com/v2/acts/localwire~ats-jobs/run-sync-get-dataset-items" \
  -H "Authorization: Bearer <YOUR_APIFY_TOKEN>" \
  -H "Content-Type: application/json" \
  -d '{"companies": ["https://jobs.ashbyhq.com/linear"], "keywords": ["engineer"], "maxResults": 50}'
```

That endpoint waits up to five minutes. For a longer run, start it with `POST /v2/acts/localwire~ats-jobs/runs` and read the run's dataset when it has finished.

With the Apify client for JavaScript:

```js
import { ApifyClient } from "apify-client";

const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor("localwire/ats-jobs").call({
  companies: ["greenhouse:monzo", "https://jobs.ashbyhq.com/linear"],
  countries: ["GB"],
  maxResults: 200,
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
```

With the Apify client for Python:

```python
from apify_client import ApifyClient

client = ApifyClient("<YOUR_APIFY_TOKEN>")
run = client.actor("localwire/ats-jobs").call(run_input={
    "companies": ["https://nvidia.wd5.myworkdayjobs.com/NVIDIAExternalCareerSite"],
    "keywords": ["engineer"],
    "maxResults": 100,
})
jobs = list(client.dataset(run["defaultDatasetId"]).iterate_items())
```

Results can be downloaded from the dataset as JSON, CSV, Excel, XML or JSON Lines.

### Use it from an AI agent (MCP)

Apify's hosted MCP server is at `https://mcp.apify.com`. Add it to any MCP client that supports remote servers and sign in with your Apify account when the browser opens (or send an `Authorization: Bearer <APIFY_TOKEN>` header).

To give the agent only this Actor as a tool, use this server URL:

```
https://mcp.apify.com?tools=localwire/ats-jobs
```

```json
{
  "mcpServers": {
    "apify": {
      "url": "https://mcp.apify.com?tools=localwire/ats-jobs"
    }
  }
}
```

The agent then sees the Actor's input fields with their descriptions and defaults. Only `companies` is required. Tell the agent to set `maxResults` (for example 50), because the default is 5,000 jobs. Questions that work well:

- "Which of these ten companies are hiring data engineers in London?"
- "List the remote roles NVIDIA posted on its Workday site this week."
- "How many open engineering jobs does each of these startups have, and what do they pay?"

### Integrations

Runs can be started on a schedule or by another system, and results can be sent on:

- **Make, n8n and Zapier** have Apify integrations that run an Actor and pass its dataset to the next step, for example to a spreadsheet, a CRM, email or a chat channel.
- **Webhooks** call your endpoint when a run succeeds or fails.
- **LangChain** and other agent frameworks can use Apify Actors as tools.
- **The Apify API** and the JavaScript and Python clients cover everything else.

### FAQ

#### Is there a Workday jobs API?

Workday does not publish a documented public API for third parties to read job postings. Every Workday career site does load its postings from JSON endpoints on its own host, without a login, and this Actor reads those. Give it the careers URL (`…myworkdayjobs.com/<Site>`) and you get every posting as structured data.

#### How do I get all jobs from a Greenhouse board?

Put the board's URL in `companies`, for example `https://job-boards.greenhouse.io/monzo`, or write `greenhouse:monzo`. The Actor reads Greenhouse's official Job Board API and returns every published job with its description in one request. Leave the filters empty to get everything.

#### Is there a Lever jobs API or an Ashby jobs API?

Yes. Lever and Ashby both publish official, unauthenticated postings APIs, and this Actor reads them. What it adds is one schema across all eleven platforms, country codes, filters and monitor mode, so you do not have to write and maintain a parser for each platform.

#### How do I find out which ATS a company uses?

Give the company's name or website. The Actor looks for a job-board link on the company's careers page, then tries the company's likely board id on each platform. The `ats` field of the output says which platform it found, and `detectedBy` says how.

#### How do I get jobs from many companies in one run?

List up to 1,000 entries in `companies`. They can be on different platforms. Each job's `input` field says which entry it came from, and the `OUTPUT` record summarises every company.

#### How do I get only new jobs since the last run?

Turn on `monitorMode` and schedule the Actor. Each run returns, and charges for, only jobs it has not returned before.

#### Does the Career Site Jobs API return salaries?

Where the employer publishes a pay range in the job board's structured fields: Lever, Ashby, Workable, Recruitee, Personio and Pinpoint. Greenhouse, SmartRecruiters, Workday, Oracle and SuccessFactors endpoints do not include pay, so the salary fields are empty there even if the description text mentions a figure.

#### How much does it cost to get 10,000 jobs?

$15.00. The price is $0.0015 per job returned, so 1,000 jobs cost $1.50.

#### Does it need proxies, a browser or a login?

No. It makes plain HTTPS requests to public endpoints, identifies itself with its own User-Agent, and never logs in.

#### How fresh is the data?

Every run reads the job boards live. There is no database in between, so you get what the careers site shows at that moment.

#### Why was a company not found?

Usually because it was given by name and its board id is not one of the obvious spellings, or because its board is on Workday, Oracle or SuccessFactors, which need a URL. Open the company's careers page, copy the URL of the page that lists its jobs, and use that.

#### Is it legal to collect job postings?

This is not legal advice. Job postings are published by employers for anyone to read, and the Actor reads only public endpoints. You are responsible for how you use the data, including the platforms' and employers' terms and any rules that apply to you.

### Limitations

- **Platforms.** Only the eleven listed. iCIMS, Taleo, Jobvite, BambooHR and Teamtailor are not supported.
- **No bot-protection evasion.** The Actor does not use proxies, solve challenges or disguise itself. A request that is refused with HTTP 403 is not retried. A rate limit (HTTP 429) or server error is retried a few times with increasing waits, honouring `Retry-After`, and then the Actor gives up on that company, records the error in `OUTPUT` and moves on to the next. If every company fails, the run fails.
- **Workday speed.** About 0.4 seconds per posting. Use keywords, `maxJobsPerCompany` or monitor mode for very large sites.
- **One request per job** for descriptions on SmartRecruiters, Oracle, SuccessFactors and Workable. Without descriptions those platforms return the listing fields only.
- **Salaries** appear only where the platform has structured pay fields and the employer filled them in.
- **Countries** are read from location text when the platform has no country field. When nearly all of a company's jobs are in one country, small towns the Actor does not recognise get that country; otherwise unusual place names leave `country` empty.
- **Names are guesses.** A company given by name is matched by board id, and two companies can share one. Check `company`, or pass the URL.
- **Greenhouse EU boards** may not be readable through the public API.
- **Not a jobs database.** The Actor reads the companies you list. It does not search across all employers by keyword.

### Data, privacy and terms

Job postings are published by employers for anyone to read. This Actor reads the platforms' public job-board endpoints only, never logs in, and does not try to get around any access control or rate limit.

Personal data is kept out of the output. There are no fields for recruiters, hiring managers or contacts, and application inboxes are not copied. In descriptions, email addresses are replaced with `[email removed]` and phone numbers in UK, North American and `+country code` formats with `[phone removed]`, and full UK postcodes are shortened to their district. A number written in an unusual local format, and names that an employer wrote into its own description, can remain.

You are responsible for how you use the data, including the platforms' and employers' terms.

This Actor is not affiliated with or endorsed by Workday, Greenhouse, Lever, Ashby, SmartRecruiters, SAP, Oracle, Workable, Recruitee, Personio or Pinpoint.

### More from this developer

Jobs:

- [Workday Jobs API](https://apify.com/localwire/workday-jobs): this Actor with a Workday-first form.
- [Reed.co.uk Jobs Scraper](https://apify.com/localwire/reed-jobs): UK job-board search in the same schema.
- [Wellfound Jobs Scraper](https://apify.com/localwire/wellfound-jobs): startup jobs in the same schema, with pay and equity.
- [Hacker News API](https://apify.com/localwire/hacker-news): stories, comments and structured "Who is hiring?" jobs.

Other data:

- [Public Tenders API](https://apify.com/localwire/uk-public-tenders): UK and EU tenders and contract awards.
- [Google Trends Trending Now](https://apify.com/localwire/google-trends-trending-now): trending searches for 125 countries.
- [App Store Reviews](https://apify.com/localwire/app-store-reviews): reviews, app details and top charts.
- [Telegram Channel Scraper](https://apify.com/localwire/telegram-channels): posts from public channels.
- [ESPN Sports Data](https://apify.com/localwire/espn-sports) and [Flashscore Results & Fixtures](https://apify.com/localwire/flashscore-sports): scores, standings and fixtures.
- [Eventbrite Scraper](https://apify.com/localwire/eventbrite-events) and [Meetup Scraper](https://apify.com/localwire/meetup-events): events by place and topic.
- [Gumtree Scraper](https://apify.com/localwire/gumtree-listings): UK classified listings.

### Feedback

Need another platform or a field we do not return, or found a board that does not work? Open an issue on the Actor's **Issues** tab and we will reply within a few days.

# Actor input Schema

## `companies` (type: `array`):

Required. One company per line: a job-board or careers-site URL (e.g. https://job-boards.greenhouse.io/monzo, https://jobs.lever.co/leverdemo, https://jobs.ashbyhq.com/linear, https://nvidia.wd5.myworkdayjobs.com/NVIDIAExternalCareerSite, https://apply.workable.com/careers, https://workwithus.pinpointhq.com, an Oracle …/hcmUI/CandidateExperience/en/sites/CX_1/requisitions URL, or a SuccessFactors careers site such as https://careers.sap.com), a company website (monzo.com), a company name (Linear), or platform:board (greenhouse:monzo, lever:leverdemo, lever-eu:acme, ashby:linear, smartrecruiters:BoschGroup, recruitee:bunq, personio:1komma5grad, workable:careers, pinpoint:workwithus, successfactors:careers.sap.com). Websites are checked for a job-board link; names are matched against each platform's public board ids, so check the company in the output. Workday and Oracle boards need their URL.

## `keywords` (type: `array`):

Keep jobs whose title, department or team contains ANY of these words or phrases (matched at the start of a word, case- and accent-insensitive), e.g. engineer, "data scientist", sales. Leave empty for every job. On Workday, SuccessFactors and Oracle the keywords are also sent to the site's own search, so fewer postings are read.

## `searchDescriptions` (type: `boolean`):

Match keywords against the full job description too (e.g. a technology like Kubernetes). Slower on SmartRecruiters, Oracle and SuccessFactors, which need one request per job for descriptions.

## `excludeKeywords` (type: `array`):

Drop jobs whose title contains ANY of these words, e.g. intern, senior.

## `countries` (type: `array`):

Keep jobs in ANY of these countries: ISO codes or names, e.g. GB, UK, Germany, US. Countries come from the job board's own fields where published, otherwise from the location text.

## `locations` (type: `array`):

Keep jobs whose location text contains ANY of these, e.g. London, Berlin, Remote.

## `remoteOnly` (type: `boolean`):

Keep only jobs marked remote by the job board, or whose location says remote.

## `departments` (type: `array`):

Keep jobs whose department or team contains ANY of these, e.g. Engineering, Sales.

## `employmentTypes` (type: `array`):

Keep only these employment types. Jobs whose type isn't published are dropped when this is set.

## `postedWithinDays` (type: `integer`):

Keep jobs first published (or, where that isn't given, last updated) in this many days. Jobs without a date are kept.

## `postedSince` (type: `string`):

Keep jobs posted on or after this date, e.g. 2026-11-01. Overrides 'Posted in the last N days'.

## `atsPlatforms` (type: `array`):

Which job-board platforms to try when a company is given by name or website. Board URLs and platform:board entries always work. Workday and Oracle boards are only found from their URLs; SuccessFactors sites are recognised when you give the careers site itself.

## `monitorMode` (type: `boolean`):

Remember which jobs each company had last time and return (and charge for) only jobs that are new since then (changeType "new"). Schedule the Actor daily to get a feed of new openings. Keep the same filters for a monitor; changing them starts it again.

## `emitRemoved` (type: `boolean`):

In monitor mode, also return jobs that have disappeared since the last run (changeType "removed"), e.g. to track roles being filled.

## `monitorEmitExistingOnFirstRun` (type: `boolean`):

On a monitor's first run every current job counts as new. Turn this off to record them silently (and not be charged for them), so later runs return only genuinely new jobs.

## `monitorStoreName` (type: `string`):

Name of the key-value store in your account that holds the monitor's memory. Use a different name for each monitor (e.g. per filter set or per client). Letters, digits and hyphens.

## `includeDescriptions` (type: `boolean`):

Include each job's full description as plain text. Turn off for smaller, faster runs (Workday still reads each posting, because its listing has no locations or dates).

## `includeHtml` (type: `boolean`):

Also include the description as HTML (descriptionHtml).

## `maxJobsPerCompany` (type: `integer`):

Stop reading a company's board after this many matching jobs. 1000 when left out. The form starts at 20 so that a first run is small and cheap; raise it to read whole boards.

## `maxResults` (type: `integer`):

Stop the run after this many jobs in total. Each job returned is charged once, so this is also the cost cap: 50 jobs is a quick, cheap sample. 5000 when left out; the form starts at 50 so that a first run is small. You can also cap spending with the run's maximum cost.

## `useDetectionCache` (type: `boolean`):

Cache the job board found for a company name or website for 30 days (in a key-value store called ats-jobs-detection-cache in your account), so later runs skip the search.

## Actor input object example

```json
{
  "companies": [
    "https://job-boards.greenhouse.io/monzo",
    "https://jobs.ashbyhq.com/linear",
    "bunq.recruitee.com"
  ],
  "keywords": [
    "engineer",
    "data scientist"
  ],
  "searchDescriptions": false,
  "countries": [
    "GB",
    "IE"
  ],
  "remoteOnly": false,
  "atsPlatforms": [
    "greenhouse",
    "lever",
    "ashby",
    "smartrecruiters",
    "recruitee",
    "personio",
    "workable",
    "pinpoint",
    "workday",
    "successfactors",
    "oracle"
  ],
  "monitorMode": false,
  "emitRemoved": false,
  "monitorEmitExistingOnFirstRun": true,
  "monitorStoreName": "ats-jobs-monitor",
  "includeDescriptions": true,
  "includeHtml": false,
  "maxJobsPerCompany": 20,
  "maxResults": 50,
  "useDetectionCache": true
}
```

# Actor output Schema

## `overview` (type: `string`):

The key facts for each job.

## `salaries` (type: `string`):

Jobs with the pay range the employer published (where they did).

## `changes` (type: `string`):

In monitor mode: which jobs are new and which were removed since the last run.

## `allResults` (type: `string`):

Every record in the run's default dataset, all fields.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "companies": [
        "https://job-boards.greenhouse.io/monzo",
        "https://jobs.ashbyhq.com/linear",
        "bunq.recruitee.com"
    ],
    "maxJobsPerCompany": 20,
    "maxResults": 50
};

// Run the Actor and wait for it to finish
const run = await client.actor("localwire/ats-jobs").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "companies": [
        "https://job-boards.greenhouse.io/monzo",
        "https://jobs.ashbyhq.com/linear",
        "bunq.recruitee.com",
    ],
    "maxJobsPerCompany": 20,
    "maxResults": 50,
}

# Run the Actor and wait for it to finish
run = client.actor("localwire/ats-jobs").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "companies": [
    "https://job-boards.greenhouse.io/monzo",
    "https://jobs.ashbyhq.com/linear",
    "bunq.recruitee.com"
  ],
  "maxJobsPerCompany": 20,
  "maxResults": 50
}' |
apify call localwire/ats-jobs --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,localwire/ats-jobs"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/tZImedJClFmphONmX/builds/od4otOHNd1gdQ3lOR/openapi.json
