# ATS Jobs: Greenhouse/Lever/Ashby/Recruitee/Personio/Teamtailor (`tamatama/ats-jobs`) Actor

Scrape open jobs from Greenhouse, Lever, Ashby, Recruitee, Personio and Teamtailor company career boards. Paste board URLs, domains or names. One normalized schema, title/location/remote filters, new & closed job monitoring. $1 per 1,000 jobs.

- **URL**: https://apify.com/tamatama/ats-jobs.md
- **Developed by:** [Otama Labs](https://apify.com/tamatama) (community)
- **Categories:** Jobs, Lead generation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.00 / 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

## ATS Jobs: Greenhouse/Lever/Ashby/Recruitee/Personio/Teamtailor

Get **every open job of the companies you choose**, straight from their own public job boards on **Greenhouse, Lever, Ashby, Recruitee, Personio and Teamtailor**. Paste job board URLs, company domains or just company names. Results are live (read at run time, not from a stale index), normalized into one table, and cost **$1 per 1,000 jobs** (plus $0.00005 per run).

Turn on **monitoring** and schedule the Actor to get only the jobs that were **added or closed** since the last run: a simple hiring-signal feed for sales prospecting, investor research, competitor tracking or recruiting.

### What you can do with it

- **Sales prospecting**: companies hiring for a role you sell into (e.g. "Head of Security", "Salesforce Admin") are likely buyers.
- **Competitor and market tracking**: see which teams your competitors are growing and where.
- **Recruiting and job search**: one feed of fresh roles from your target companies, filtered by title, location or remote.
- **AI agents**: give an agent a list of companies and get structured, current openings back.

### Output example

One row per job, with the same fields for every ATS:

```json
{
  "company": "Ramp",
  "title": "Manager, Account Manager | Growth",
  "department": "Sales",
  "team": "Account Manager",
  "location": "New York, NY (HQ)",
  "allLocations": ["New York, NY (HQ)", "San Francisco, CA"],
  "countryCode": "US",
  "workplaceType": "hybrid",
  "isRemote": false,
  "employmentType": "FullTime",
  "salaryMin": 180000,
  "salaryMax": 247000,
  "salaryCurrency": "USD",
  "salaryInterval": "year",
  "salaryText": "$180K – $247K • Offers Equity • Offers Commission",
  "postedAt": "2026-10-13T15:07:59.917000+00:00",
  "url": "https://jobs.ashbyhq.com/ramp/190c265a-...",
  "applyUrl": "https://jobs.ashbyhq.com/ramp/190c265a-.../application",
  "ats": "ashby",
  "boardSlug": "ramp",
  "jobId": "190c265a-ca4f-48b7-b2a4-13412299249d",
  "change": null,
  "matchedBy": "direct",
  "input": "https://jobs.ashbyhq.com/ramp",
  "scrapedAt": "2026-10-14T06:01:12+00:00"
}
```

Fields a board does not publish are `null` (for example many boards do not publish salaries).

### How to use

1. Put your companies in **Companies**, one per line (job board URLs are the most reliable).
2. Optionally add title, location, remote or date filters.
3. Click **Start**. Jobs appear in the **Output** tab; download them as JSON, CSV or Excel, or read them through the API.
4. For a hiring-signal feed, turn on monitoring and add a schedule (see below).

### Input

| Field | What it does |
|---|---|
| **Companies** | One per line. A job board URL works best: `https://boards.greenhouse.io/airbnb`, `https://jobs.lever.co/palantir`, `https://jobs.ashbyhq.com/ramp`, `https://bunq.recruitee.com`, `https://1komma5grad.jobs.personio.de`, `https://tibber.teamtailor.com`. Teamtailor career sites on the company's own domain work too (`https://jobs.tibber.com` or `teamtailor:jobs.tibber.com`). You can also write `greenhouse:airbnb`, a domain (`stripe.com`) or a company name (`Notion`). |
| Title must contain / must not contain | Case-insensitive, whole-word keyword filters on the job title (`AI` matches "AI Engineer", not "Retail"). |
| Location contains | Whole words, e.g. `London`, `Germany`, `US`, `Remote`. |
| Remote jobs only | Keep only jobs whose workplace type is remote (hybrid jobs are not remote). |
| Posted within (days) | Only jobs published in the last N days. |
| Max jobs per company | Newest first. 0 = all. |
| Include job description | Adds the full description as plain text. |
| Only new and closed jobs since the last run | Monitoring mode (see below). |
| Monitor name | Keep separate memories for different company lists. |

**How companies are matched.** Board URLs and `ats:slug` are read directly. For a domain the Actor looks for job board links on the company website (only pages its `robots.txt` allows), then tries likely board names on each supported ATS. For a company name it tries likely board names. Each job has a `matchedBy` field (`direct`, `website` or `guess`); please check `guess` matches, because two companies can share a name. The run summary (`SUMMARY` in the key-value store) lists, for each input, the board found and a status: `ok`, `not_found` (no supported board), `error` (the input could not be read or a board did not answer; the reason is included) or `skipped_cost_limit`. One bad input never stops the run.

### Monitoring: new and closed jobs

1. Turn on **Only new and closed jobs since the last run** and set a **Monitor name**.
2. The first run returns the matching jobs (`change: "new"`) and remembers the ones it returned.
3. Schedule the Actor (e.g. daily). Each later run returns only matching jobs you have not received yet (`change: "new"`) and jobs you received earlier that are no longer on the board (`change: "closed"`).

Details:

- Every job is delivered as new exactly once. If **Max jobs per company** or your maximum cost per run stops the output early, the remaining jobs come in the next runs; nothing is lost.
- A job is reported closed only when it disappears from the company's board, not when it stops matching your filters (for example when it gets older than **Posted within (days)**).
- Closed-job rows are **free**.
- Use a separate monitor name for each company list. If you change the title or location filters of a monitor, jobs that start to match are delivered as new.

### Pricing

Pay per event: **$1.00 per 1,000 jobs** in the output, plus a tiny Apify start fee of $0.00005 per run. You are not charged for inputs where no board was found, for jobs removed by your filters, or for closed-job rows. Set a maximum cost per run in the run options if you want a hard cap.

### Supported job boards

| ATS | Board URL looks like |
|---|---|
| Greenhouse | `boards.greenhouse.io/{company}`, `job-boards.greenhouse.io/{company}` |
| Lever | `jobs.lever.co/{company}` (and `jobs.eu.lever.co`) |
| Ashby | `jobs.ashbyhq.com/{company}` |
| Recruitee | `{company}.recruitee.com` |
| Personio | `{company}.jobs.personio.de` (and `.com`), read from Personio's official XML job feed |
| Teamtailor | `{company}.teamtailor.com` or the company's own career site domain, read from Teamtailor's official RSS job feed (up to 3,000 jobs per site) |

Companies that run their own career site without one of these systems (for example Google or Apple) are not supported and show up in the summary as not found.

### Responsible use

The Actor only reads job boards that the companies publish through their ATS's public job board API, spaces requests to each host (Lever's `Crawl-delay` is respected), and only reads company websites where `robots.txt` allows it. It does not log in anywhere and does not collect personal data about candidates or employees. You are responsible for how you use the data.

### FAQ

**A company was not found.** Paste its job board URL directly (open the company's careers page, click a job, and copy the board address). If the board is on another ATS, it is not supported yet.

**Can I get more than one company per run?** Yes, add as many lines as you like. Boards are read in parallel.

**Why is the salary empty?** The company does not publish it on the board.

# Actor input Schema

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

One per line. Best: a job board URL (e.g. https://boards.greenhouse.io/airbnb, https://jobs.lever.co/palantir, https://jobs.ashbyhq.com/ramp, https://bunq.recruitee.com, https://1komma5grad.jobs.personio.de, https://tibber.teamtailor.com). Also works: "greenhouse:airbnb", "teamtailor:jobs.tibber.com" (Teamtailor career site on the company's own domain), a company website or domain (stripe.com) or a company name. For domains and names the Actor looks for job board links on the website and then tries likely board names; check the matchedBy field for those.

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

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

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

Drop jobs whose title contains any of these words.

## `locationKeywords` (type: `array`):

Keep only jobs whose location text contains one of these, e.g. "London", "Germany", "Remote".

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

Keep only jobs the board marks as remote (or whose location says remote).

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

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

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

Newest first. 0 = all jobs.

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

Add the full job description as plain text. Makes the output much larger.

## `onlyNewSinceLastRun` (type: `boolean`):

Monitoring mode. The first run returns all jobs and remembers them; later runs return only new jobs (change = "new") and jobs that disappeared (change = "closed", free of charge). Schedule the Actor to get a feed of hiring changes.

## `monitorName` (type: `string`):

Keeps separate memories for different company lists. Use the same name in every scheduled run of the same list.

## `maxConcurrency` (type: `integer`):

Requests to each job board host are always spaced politely.

## Actor input object example

```json
{
  "companies": [
    "https://boards.greenhouse.io/airbnb",
    "https://jobs.ashbyhq.com/ramp"
  ],
  "remoteOnly": false,
  "postedWithinDays": 0,
  "maxJobsPerCompany": 20,
  "includeDescription": false,
  "onlyNewSinceLastRun": false,
  "monitorName": "default",
  "maxConcurrency": 5
}
```

# Actor output Schema

## `jobs` (type: `string`):

No description

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

No description

# 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://boards.greenhouse.io/airbnb",
        "https://jobs.ashbyhq.com/ramp"
    ],
    "maxJobsPerCompany": 20
};

// Run the Actor and wait for it to finish
const run = await client.actor("tamatama/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://boards.greenhouse.io/airbnb",
        "https://jobs.ashbyhq.com/ramp",
    ],
    "maxJobsPerCompany": 20,
}

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

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,tamatama/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/5JffaChhwVGkDIlBh/builds/JNFmX9fYTDOS9bE2C/openapi.json
