# Career Site Jobs API: Greenhouse, Lever, Ashby & More (`atsfeed/ats-job-search`) Actor

Search open jobs from 19,000 company career sites on Greenhouse, Lever, Ashby, Workable, SmartRecruiters, Recruitee, Personio and Breezy. Every job is checked live, and you are not charged for closed ones.

- **URL**: https://apify.com/atsfeed/ats-job-search.md
- **Developed by:** [Velavalapalli Mohana Durga Sai Ram](https://apify.com/atsfeed) (community)
- **Categories:** Jobs, Lead generation, Automation
- **Security:** Limited permissions
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.00 / 1,000 job returneds

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

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

### What does Career Site Jobs API do?

Search open jobs straight from company career sites, across **Greenhouse, Lever, Ashby, Workable, SmartRecruiters, Recruitee, Personio and Breezy**, in one call. Every job is **checked live at its source during your run**, and **closed jobs are skipped at no charge**. The index holds about **730,000 open jobs from 19,000 companies** and is refreshed daily.

Use it as a **job postings API** or a jobs scraper: send keywords, places and filters, and get back clean records with pay, skills, seniority, workplace type and visa wording already pulled out. The data is ready for a job board, a recruiting pipeline, an AI agent or a sales list.

### Why use Career Site Jobs API?

- **No dead links.** Each job is read from the employer's own applicant tracking system while your run is in progress. If the job has closed, it is dropped and you pay nothing for it.
- **Location search that understands people.** Type `Bangalore` or `Bengaluru`, `UK` or `United Kingdom`, a city, a state or a country code. A city returns jobs in that city, not the whole country.
- **Predictable cost.** You pay per job returned. Set **Maximum jobs** and you know your top cost before the run starts.
- **Daily feeds without repeats.** Turn on **Only jobs not returned before**, schedule the Actor, and each run delivers only the jobs you have not seen.
- **Direct from employers.** Results come from company job boards, not from reposted aggregator listings.
- **Works with your tools.** Run it through the API, on a schedule, with webhooks, or from Zapier, Make, n8n, Google Sheets and AI agents.

#### Who uses job postings data like this?

- **Job boards** that fill a niche with fresh, direct-apply listings for one field or region.
- **Sales teams** looking for buying signals: a company hiring its third SDR or naming Salesforce in a posting is telling you something.
- **AI agents and automations** that search jobs in n8n, Make, Zapier or your own code.
- **Researchers** tracking who is hiring, what they pay and which tools they ask for.

### What data can Career Site Jobs API extract?

| Field | Type | Description |
|---|---|---|
| `title`, `company` | text | Job title as the employer wrote it, and the hiring company |
| `location`, `countries` | text, list | Location text and ISO country codes |
| `workplaceType` | text | `remote`, `hybrid`, `onsite` or `unspecified` |
| `salary` | object | Stated pay with `min`, `max`, `currency` and `period` |
| `skills` | list | Tools and technologies named in the description |
| `seniority`, `category` | text | Detected level, such as `senior`, and job family, such as `data_ai` |
| `visaSponsorship` | text | `offered` or `not_offered` when the posting says so |
| `postedDate`, `firstSeenDate` | date | When the job was posted, and when this index first saw it |
| `jobUrl`, `applyUrl`, `careersPageUrl` | link | The posting, the application form and the company's job board |
| `description` | text | Full description, read live during your run |
| `verifiedLive`, `checkedAt` | yes/no, date | Proof that the job was open when you received it |

### How to scrape jobs from company career sites

1. Enter **job title keywords**, such as `data engineer` or `"account executive"`.
2. Add **locations** and any other filters, or leave them empty.
3. Set **Maximum jobs** and click **Start**.
4. Download the results, or read them through the API.

#### Example input

```json
{
  "titleKeywords": ["data engineer", "analytics engineer"],
  "excludeTitleKeywords": ["intern"],
  "locations": ["Germany", "Remote"],
  "postedWithinDays": 7,
  "skills": ["snowflake", "dbt"],
  "maxResults": 200
}
```

### How much does it cost to scrape career site jobs?

You pay per job returned, and higher Apify plans pay less per job. The pricing panel on this page shows the price for your plan. On the Free and Starter plans:

| Jobs returned | Cost |
|---|---|
| 100 | $0.15 |
| 1,000 | $1.50 |
| 10,000 | $15.00 |

Closed jobs and jobs rejected by your description filters are not charged. Platform usage is included, so there is no separate compute bill, and Apify's free plan credit covers your first few thousand jobs each month.

### Input

See the **Input** tab for every option. The ones that matter most:

| Option | What it does |
|---|---|
| Job title keywords | Match any entry. Words in any order, or use double quotes for an exact phrase |
| Exclude title keywords | Skip titles containing these |
| Locations | City, state, country or country code, in plain words |
| Posted within the last N days | 1 for today, 7 for a week, 0 for any date |
| Only these companies | Names, board names or website domains |
| Only these sources | Limit to specific applicant tracking systems |
| Remote only, workplace type | Remote, hybrid or on-site |
| Seniority, category, employment type | Structured filters |
| Skills | Tools and technologies named in the description |
| Only jobs that state pay, minimum yearly pay | Pay filters |
| Visa and clearance filters | Based on the wording in the description |
| Description keywords | Checked against the live description. You pay only for jobs that pass |
| Only jobs not returned before | For scheduled runs: delivers only new jobs |

### Output

Download the dataset as JSON, CSV, Excel, XML, RSS or HTML. Each job looks like this:

#### Example output

```json
{
  "id": "greenhouse:acme:5470571008",
  "title": "Senior Data Engineer",
  "company": "Acme",
  "location": "Berlin, Germany",
  "countries": ["DE"],
  "workplaceType": "hybrid",
  "employmentType": "full_time",
  "seniority": "senior",
  "category": "data_ai",
  "department": "Data",
  "postedDate": "2026-11-04",
  "firstSeenDate": "2026-11-05",
  "salary": { "min": 80000, "max": 100000, "currency": "EUR", "period": "year" },
  "skills": ["python", "snowflake", "dbt", "airflow"],
  "visaSponsorship": "offered",
  "securityClearanceRequired": false,
  "jobUrl": "https://job-boards.greenhouse.io/acme/jobs/5470571008",
  "applyUrl": "https://job-boards.greenhouse.io/acme/jobs/5470571008",
  "careersPageUrl": "https://job-boards.greenhouse.io/acme",
  "source": "greenhouse",
  "verifiedLive": true,
  "checkedAt": "2026-11-05T17:59:14.051Z",
  "description": "About the role..."
}
```

### Tips for faster and cheaper runs

- Set **Posted within the last N days**. Reading one week of jobs is much faster than reading every date.
- Turn off **Include full job description** when you only need the structured fields.
- Put a title in double quotes for an exact phrase, such as `"product manager"`.
- For daily feeds, keep the same filters or set a **History name**, so **Only jobs not returned before** keeps its memory.

### Use Career Site Jobs API with the API and AI agents

Start a run and read the results with the Apify API client for Node.js:

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

const client = new ApifyClient({ token: 'YOUR_APIFY_TOKEN' });
const run = await client.actor('atsfeed/ats-job-search').call({
  titleKeywords: ['data engineer'],
  locations: ['Germany'],
  maxResults: 100,
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
```

Or for Python:

```python
from apify_client import ApifyClient

client = ApifyClient("YOUR_APIFY_TOKEN")
run = client.actor("atsfeed/ats-job-search").call(run_input={"titleKeywords": ["data engineer"], "maxResults": 100})
items = client.dataset(run["defaultDatasetId"]).list_items().items
```

AI agents in Claude, ChatGPT, Cursor or any MCP client can call this Actor as a tool through the Apify MCP server at `mcp.apify.com`. The **API** tab on this page has more examples.

### FAQ

#### Is it legal to scrape job postings from career sites?

This Actor reads public job listings from endpoints that the job board vendors publish for displaying jobs. It does not log in, solve CAPTCHAs or get around access controls, and it does not collect recruiter contact details. Postings belong to the employers who publish them, so follow the rules that apply to how you reuse them, and link back to the original job when you display it.

#### How fresh are the jobs?

The index is rebuilt every day, and each job is checked live at its source while your run is in progress.

#### Why did I get fewer jobs than I asked for?

Closed jobs and duplicates are skipped. Try fewer filters, a longer date window or broader keywords.

#### Can I get only new jobs every day?

Yes. Turn on **Only jobs not returned before** and schedule the Actor. Each run skips the jobs it already delivered to you.

#### Which job sites does it cover?

Public job boards on Greenhouse, Lever, Ashby, Workable, SmartRecruiters, Recruitee, Personio and Breezy. It does not include LinkedIn, Indeed or other job boards.

### Coverage and accuracy

- **Index size, November 2026:** about 730,000 open jobs from 19,000 companies. About 170,000 state pay, and about 500,000 have skills and visa wording read from the full description.
- **By source:** SmartRecruiters 290,000, Greenhouse 160,000, Workable 85,000, Lever 73,000, Ashby 52,000, Breezy 28,000, Recruitee 19,000, Personio 10,000.
- **By region:** North America 390,000, Europe 190,000, Asia-Pacific 57,000, India 35,000, Middle East and Africa 26,000, Latin America 24,000, and 30,000 remote jobs open to any country. A job listed in two regions counts in both.
- Coverage is limited to public job boards of the supported systems and is refreshed daily. It does not include LinkedIn, Indeed or other job boards, or systems not listed above. Run-time summary numbers are saved in the `SUMMARY` record of each run.
- Skills, seniority, category, salary found in text and visa wording come from fixed rules applied to the employer's own words. They are helpful but can be wrong, so check what matters. Visa and clearance values show what a posting says, not legal status.
- Some sources do not state a posting date. In that case the date this index first saw the job is used.
- Skills and visa wording are only available for jobs where the source shared a description when indexed. Filters on those fields skip jobs without them.

### Related Actors

- [Daily Jobs Feed](https://apify.com/atsfeed/daily-jobs-feed): every new job from company career sites in one scheduled run.
- [Remote Jobs Scraper](https://apify.com/atsfeed/remote-jobs-search): remote jobs straight from company career sites.
- [Salary Benchmarks](https://apify.com/atsfeed/job-salary-benchmarks): pay ranges for any job title and location.
- [Hiring Signals & Technographics](https://apify.com/atsfeed/hiring-signals-technographics): companies hiring for a role or naming a tool in their postings.
- Job search for a single source: [Greenhouse](https://apify.com/atsfeed/greenhouse-jobs-search), [Lever](https://apify.com/atsfeed/lever-jobs-search), [Ashby](https://apify.com/atsfeed/ashby-jobs-search), [Workable](https://apify.com/atsfeed/workable-jobs-search), [SmartRecruiters](https://apify.com/atsfeed/smartrecruiters-jobs-search).

### Questions

Found a wrong result, or want another source added? Open an issue on the **Issues** tab with an example.

# Actor input Schema

## `titleKeywords` (type: `array`):

A job matches if its title contains any entry. Words in an entry can be in any order: "data engineer" also finds "Engineer, Data". Put an entry in double quotes for an exact phrase. Leave empty for all titles.

## `excludeTitleKeywords` (type: `array`):

Skip jobs whose title contains any of these, for example "intern" or "manager".

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

Any city, state, country or two-letter country code, in plain words. Common spellings work: Bangalore and Bengaluru, UK and United Kingdom. Leave empty for worldwide.

## `includeGlobalRemote` (type: `boolean`):

Applies when you set locations. Keeps remote jobs that do not name a country.

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

1 returns jobs posted today (UTC), 7 returns the last week. Use 0 for any date. Scanning all dates takes longer.

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

The run stops after this many jobs. You pay per job returned, so this also caps your cost.

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

Company names, career board names or website domains, such as "Stripe" or "stripe.com".

## `excludeCompanies` (type: `array`):

Skip jobs from companies whose name contains any of these.

## `ats` (type: `array`):

Limit results to specific applicant tracking systems.

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

Only jobs marked remote by the employer or in the location text.

## `workplaceTypes` (type: `array`):

Filter by workplace. "Not stated" covers jobs that do not say.

## `seniority` (type: `array`):

Detected from the job title.

## `categories` (type: `array`):

Detected from the job title and department.

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

Jobs that do not state a type are left out when this is set.

## `skills` (type: `array`):

Matches tools named in the job description, such as python, snowflake, salesforce or hubspot. Use lowercase. Works on jobs enriched from a full description, which is most but not all jobs.

## `salaryDisclosedOnly` (type: `boolean`):

Keep only jobs with a salary from the employer or found in the description.

## `minAnnualSalary` (type: `integer`):

Compares the top of the stated range, converted to yearly when pay is hourly or monthly. Applies only to jobs in the currency below.

## `salaryCurrency` (type: `string`):

Currency used by the minimum pay filter.

## `visaSponsorshipOnly` (type: `boolean`):

Based on wording in the description. Confirm with the employer.

## `excludeNoVisaSponsorship` (type: `boolean`):

Keeps jobs that say nothing about sponsorship.

## `excludeClearanceRequired` (type: `boolean`):

Skip jobs that mention a required security clearance.

## `includeDescription` (type: `boolean`):

Adds the description as plain text, read live from the source. Turn off for a faster run with only structured fields.

## `includeDescriptionHtml` (type: `boolean`):

Adds the original HTML when the source provides it.

## `descriptionKeywords` (type: `array`):

Checked against each live description. You are charged only for jobs that pass. Slower than title keywords, so pair it with other filters.

## `excludeDescriptionKeywords` (type: `array`):

Skip jobs whose live description contains any of these.

## `verifyLive` (type: `boolean`):

Reads each job from its source before returning it. Closed jobs are skipped at no charge. Always on when descriptions are included.

## `dedupe` (type: `boolean`):

Returns one job when a company lists the same title and location more than once.

## `onlyNewJobs` (type: `boolean`):

For scheduled runs. Remembers delivered jobs in a key-value store in your account and skips them next time. Changing any filter starts a new history, unless you set a history name below.

## `deltaKey` (type: `string`):

Optional name for the "only new jobs" history, so you can change filters and keep it. Example: "sales-jobs-feed".

## Actor input object example

```json
{
  "titleKeywords": [
    "software engineer"
  ],
  "includeGlobalRemote": true,
  "postedWithinDays": 7,
  "maxResults": 20,
  "remoteOnly": false,
  "salaryDisclosedOnly": false,
  "salaryCurrency": "USD",
  "visaSponsorshipOnly": false,
  "excludeNoVisaSponsorship": false,
  "excludeClearanceRequired": false,
  "includeDescription": true,
  "includeDescriptionHtml": false,
  "verifyLive": true,
  "dedupe": true,
  "onlyNewJobs": false
}
```

# Actor output Schema

## `results` (type: `string`):

One item per open job, checked live at its source.

## `summary` (type: `string`):

How many jobs matched, were returned, or were skipped because they had closed.

# 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 = {
    "titleKeywords": [
        "software engineer"
    ],
    "postedWithinDays": 7,
    "maxResults": 20
};

// Run the Actor and wait for it to finish
const run = await client.actor("atsfeed/ats-job-search").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 = {
    "titleKeywords": ["software engineer"],
    "postedWithinDays": 7,
    "maxResults": 20,
}

# Run the Actor and wait for it to finish
run = client.actor("atsfeed/ats-job-search").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 '{
  "titleKeywords": [
    "software engineer"
  ],
  "postedWithinDays": 7,
  "maxResults": 20
}' |
apify call atsfeed/ats-job-search --silent --output-dataset

```

## MCP server setup

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

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/QbnID5naULrLq4OLa/builds/lEPJPAizrchsS6Ja5/openapi.json
