# Company Jobs API: Greenhouse, Lever, Ashby & 7 more ATS (`globose_talent_mn9/ats-jobs-api`) Actor

Every open job from company career sites on 10 ATS: Greenhouse, Lever, Ashby, Workable, SmartRecruiters, Recruitee, Personio, Teamtailor, BambooHR, Breezy. One normalized format from public job-board feeds. Auto-detects the ATS, filters, extracts salary, only-new mode.

- **URL**: https://apify.com/globose_talent_mn9/ats-jobs-api.md
- **Developed by:** [Andrew Shamah](https://apify.com/globose_talent_mn9) (community)
- **Categories:** Jobs, Lead generation, Automation
- **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 results

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

## Company Jobs API: Greenhouse, Lever, Ashby, Workable, SmartRecruiters, Recruitee, Personio, Teamtailor, BambooHR, Breezy

Get every open job from a company's career page as clean, normalized JSON. Paste career-page URLs or company slugs. The Actor detects which applicant-tracking system (ATS) the company uses and reads the company's **public job-board API or feed**. It uses no proxies or logins. Only two cases read a public job page: Personio jobs whose feed has no description text, and Breezy descriptions.

### Why use it

- **Ten ATSs, one schema.** Greenhouse, Lever (US and EU), Ashby, Workable, SmartRecruiters, Recruitee, Personio, Teamtailor, BambooHR and Breezy all return the same fields, so you can mix US and European companies freely.
- **Auto-detection.** Type `stripe` or paste `https://jobs.ashbyhq.com/ramp`. You don't need to know which ATS a company uses.
- **Normalized salary.** Salary comes from the ATS when the company publishes it there (Lever, Ashby, Recruitee, Personio, BambooHR, Breezy). Otherwise it is parsed from pay-transparency text in the description, e.g. `$102,000—$120,000 USD`. `salarySource` tells you which method was used.
- **Only-new mode** for monitoring. Schedule the Actor and get only jobs it hasn't returned before for the same company list. Pair it with an Apify integration such as Slack, email or a webhook to get job alerts.
- **Filters:** title keywords, excluded keywords, location text, remote only and posted within N days.
- **Privacy by default.** Email addresses and phone numbers inside job descriptions are redacted (you can turn this off). No candidate or employee data is collected.
- **Failures are visible and free.** A company that can't be found produces a clear error row in the dataset, and you are not charged for it.

### Input examples

```json
{
  "companies": ["greenhouse:airbnb", "https://jobs.lever.co/palantir", "ramp", "personio:ottonova", "https://polestar.teamtailor.com", "bamboohr:rei", "breezy:ninjaholdings"],
  "keywords": ["engineer"],
  "locations": ["Remote", "London"],
  "maxJobsPerCompany": 200
}
```

Accepted forms for each company:

| Form | Example |
|---|---|
| Career-page URL | `https://boards.greenhouse.io/airbnb`, `https://jobs.lever.co/palantir`, `https://jobs.ashbyhq.com/ramp`, `https://apply.workable.com/huggingface`, `https://jobs.smartrecruiters.com/BoschGroup`, `https://bunq.recruitee.com`, `https://ottonova.jobs.personio.de`, `https://polestar.teamtailor.com`, `https://rei.bamboohr.com/careers`, `https://ninjaholdings.breezy.hr` |
| `ats:slug` | `greenhouse:stripe`, `lever:spotify`, `ashby:openai`, `personio:1komma5grad`, `teamtailor:tibber`, `bamboohr:rei`, `breezy:ninjaholdings` |
| Bare slug (auto-detect) | `figma`, `notion`, `tibber` |

SmartRecruiters company IDs are case-sensitive, e.g. `BoschGroup`. Auto-detection checks all ten ATSs in parallel and chooses the board with the most open jobs. For example, `ramp` has an Ashby board with 172 jobs and an old Greenhouse board with 1 job, so Ashby is chosen. All candidates are listed in `SUMMARY`. To force a specific board, use `ats:slug`.

### Output

There is one dataset item per job. The fields are the same for every ATS, and a field is `null` when the source doesn't provide it.

```json
{
  "ats": "ashby", "companySlug": "ramp", "company": "ramp",
  "jobId": "34413f8d-…", "title": "Security Engineer, Cloud",
  "department": "Engineering", "team": "Backend",
  "location": "New York, NY (HQ)", "locations": ["New York, NY (HQ)", "Remote (US)", "Miami, FL"],
  "country": "USA", "isRemote": true, "workplaceType": "Hybrid", "employmentType": "FullTime",
  "postedAt": "2026-04-07T17:12:35.753Z", "updatedAt": null,
  "url": "https://jobs.ashbyhq.com/ramp/34413f8d-…", "applyUrl": "https://jobs.ashbyhq.com/ramp/34413f8d-…/application",
  "salaryMin": 211400, "salaryMax": 290600, "salaryCurrency": "USD", "salaryPeriod": "YEAR",
  "salaryText": "$211.4K – $290.6K • Offers Equity", "salarySource": "ats",
  "descriptionText": "ABOUT RAMP …", "descriptionHtml": "<p>…",
  "input": "https://jobs.ashbyhq.com/ramp", "scrapedAt": "2026-10-28T12:54:15.318Z", "error": null
}
```

The `SUMMARY` record in the default key-value store lists each company with its job count or error.

**Field coverage in our test run** (910 jobs from 8 companies, 28 Oct 2026): title, location, posting date, URL and description were present for 100% of jobs. Salary coverage depends on what companies publish: Ashby 68–95%, Greenhouse 65–78%, Lever 64%, SmartRecruiters about 2%. Greenhouse doesn't expose employment type, and Lever and SmartRecruiters don't expose department in the same way.

**v1.1 sources, tested 28 Oct 2026:** Personio (1KOMMA5°, 309 jobs; ottonova) had title, location, date, department, employment type and description on 100% of jobs, plus `seniority` and `keywords`. Teamtailor (Polestar, Tibber) had title, location, country, date, description and on-site/hybrid/remote status on 100%. BambooHR (REI) had every field including salary where published. Breezy (NinjaHoldings) had salary on 100% of jobs.

v1.1 added two fields, `seniority` and `keywords`. They are filled only where the ATS provides them (Personio, BambooHR) and are `null` elsewhere. No existing field changed.

### Pricing

This Actor uses pay-per-event pricing:

- A small **Actor start** fee, which is Apify's standard synthetic event.
- A **per-job** fee for each job written to the dataset.

Error rows are free. Set *Maximum cost per run* in the run options, and the Actor stops cleanly when it reaches that limit. See the Pricing tab for current prices.

### Limits and honest notes

- The Actor only covers companies that use one of the ten supported ATSs with a public job board. Workday, iCIMS, Taleo, SuccessFactors and similar systems are **not** supported.
- The data is whatever the company publishes. The Actor doesn't verify or enrich it.
- For SmartRecruiters, descriptions need one extra API call per job, so large boards like Bosch (5,000+ jobs) are slower. Set `includeDescription: false` or `maxJobsPerCompany` for speed.
- Personio's XML feed often has no description text. In that case the Actor reads the public job page, which is one extra request per job, and only for jobs that pass your filters. Personio doesn't provide a country field.
- BambooHR and Breezy need one extra request per job for the description. BambooHR also needs it for the posting date. Set `includeDescription: false` for the fastest runs. BambooHR jobs then have no `postedAt`.
- Personio and Teamtailor boards on a custom domain can be given as `personio:careers.example.com` or `teamtailor:jobs.example.com`.
- Only-new mode keys its memory on the exact company list. If you change the list, a new memory starts.

### Legal and data use

The Actor uses the job-board endpoints that each ATS documents for public career sites, for example the [Greenhouse Job Board API](https://developers.greenhouse.io/job-board.html), [Lever Postings API](https://github.com/lever/postings-api) and [Ashby public job posting API](https://developers.ashbyhq.com/docs/public-job-posting-api). Job postings are information that employers publish on purpose. The Actor does not log in, bypass any protection or collect personal data. You are responsible for using the results in line with applicable law and the source's terms.

# Actor input Schema

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

One per line. Accepts a career-page URL (e.g. https://boards.greenhouse.io/airbnb, https://jobs.lever.co/palantir, https://jobs.ashbyhq.com/ramp, https://apply.workable.com/huggingface, https://jobs.smartrecruiters.com/BoschGroup, https://bunq.recruitee.com, https://ottonova.jobs.personio.de, https://polestar.teamtailor.com, https://rei.bamboohr.com/careers, https://ninjaholdings.breezy.hr), an explicit 'ats:slug' (greenhouse:airbnb, lever:palantir, ashby:ramp, workable:huggingface, smartrecruiters:BoschGroup, recruitee:bunq, personio:ottonova, teamtailor:polestar, bamboohr:rei, breezy:ninjaholdings), or just a slug like 'airbnb', in which case every ATS is tried in turn.

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

Keep only jobs whose title contains at least one of these words (case-insensitive). Leave empty for all jobs.

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

Drop jobs whose title contains any of these words.

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

Keep only jobs where any location contains one of these strings, e.g. 'London', 'Germany', 'Remote'.

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

Keep only jobs the ATS marks as remote, or whose location says remote.

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

Keep only jobs published or updated in the last N days. 0 = no limit. Jobs without a date are kept.

## `onlyNew` (type: `boolean`):

Remember job IDs between runs (in a named key-value store in your account) and return only jobs not seen before. Ideal for scheduled monitoring.

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

Add the full description as plain text (and HTML). SmartRecruiters needs one extra request per job for this.

## `redactContacts` (type: `boolean`):

Replace e-mail addresses and phone numbers that appear inside job descriptions with \[redacted].

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

Stop after this many matching jobs per company. 0 = no limit.

## `maxJobsTotal` (type: `integer`):

Stop the run after this many jobs. 0 = no limit.

## Actor input object example

```json
{
  "companies": [
    "greenhouse:airbnb",
    "https://jobs.ashbyhq.com/ramp",
    "lever:palantir"
  ],
  "keywords": [],
  "excludeKeywords": [],
  "locations": [],
  "remoteOnly": false,
  "postedWithinDays": 0,
  "onlyNew": false,
  "includeDescription": true,
  "redactContacts": true,
  "maxJobsPerCompany": 0,
  "maxJobsTotal": 0
}
```

# Actor output Schema

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

All job results in the default dataset, shown with the 'overview' table view.

# 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": [
        "greenhouse:airbnb",
        "https://jobs.ashbyhq.com/ramp",
        "lever:palantir"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("globose_talent_mn9/ats-jobs-api").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": [
        "greenhouse:airbnb",
        "https://jobs.ashbyhq.com/ramp",
        "lever:palantir",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("globose_talent_mn9/ats-jobs-api").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": [
    "greenhouse:airbnb",
    "https://jobs.ashbyhq.com/ramp",
    "lever:palantir"
  ]
}' |
apify call globose_talent_mn9/ats-jobs-api --silent --output-dataset

```

## MCP server setup

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

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/mFuk88y0oANIxiyj8/builds/qtOMWd5fhgcIv3I9G/openapi.json
