# Multi-ATS Jobs Scraper (Greenhouse, Lever, Ashby) (`dami_studio/multi-ats-jobs-scraper`) Actor

Scrape open job listings from the three big ATS job boards — Greenhouse, Lever and Ashby — straight from their public JSON APIs. No key, no login. Pass companies as "ats:token" (e.g. greenhouse:stripe) and get every posting normalized to one clean schema.

- **URL**: https://apify.com/dami\_studio/multi-ats-jobs-scraper.md
- **Developed by:** [Dami's Studio](https://apify.com/dami_studio) (community)
- **Categories:** Jobs, Integrations, Lead generation
- **Stats:** 3 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: 5.00 out of 5 stars

## Pricing

$3.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.

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

## What's an Apify Actor?

Actors are a software tools running on the Apify platform, for all kinds of web data extraction and automation use cases.
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.
Actors are written with capital "A".

## 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.
The best way to integrate Actors is as follows.

In JavaScript/TypeScript projects, use official [JavaScript/TypeScript client](https://docs.apify.com/api/client/js.md):

```bash
npm install apify-client
```

In Python projects, use official [Python client library](https://docs.apify.com/api/client/python.md):

```bash
pip install apify-client
```

In shell scripts, use [Apify CLI](https://docs.apify.com/cli/docs.md):

````bash
# MacOS / Linux
curl -fsSL https://apify.com/install-cli.sh | bash
# Windows
irm https://apify.com/install-cli.ps1 | iex
```bash

In AI frameworks, you might use the [Apify MCP server](https://docs.apify.com/platform/integrations/mcp.md).

If your project is in a different language, use the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).


# README

## Multi-ATS Jobs Scraper (Greenhouse · Lever · Ashby)

Scrape open job listings straight from the **public JSON APIs** of the three most common applicant-tracking systems — Greenhouse, Lever and Ashby. No API key, no login, no anti-bot to fight. Point it at a list of company boards and get every posting back in **one normalized schema**.

Thousands of companies post their jobs through exactly these three boards. Instead of writing a scraper per company, give this actor a list like `["greenhouse:stripe","lever:spotify","ashby:ramp"]` and it figures out the right endpoint for each and merges the results.

### Input

| Field | Notes |
|---|---|
| `companies` | Array of `"ats:token"` strings. `ats` is `greenhouse`, `lever`, or `ashby`; `token` is the company's board slug. e.g. `greenhouse:stripe`, `lever:spotify`, `ashby:openai`. |
| `ats` + `company` | Convenience pair for a single board (e.g. `ats: "greenhouse"`, `company: "stripe"`). Ignored when `companies` is set. |
| `maxItems` | Max postings per company. `0` (default) = all open postings. |
| `proxyConfiguration` | Optional, **off by default**. These public APIs have no anti-bot, so no proxy is needed. Only enable one if you hit IP-based rate limits across many boards. |

#### Where do I find the token?

It's the slug in the public careers URL:

- Greenhouse → `boards.greenhouse.io/<token>` (also `<token>.greenhouse.io`)
- Lever → `jobs.lever.co/<company>`
- Ashby → `jobs.ashbyhq.com/<name>`

### Output

One dataset row per job posting, deduped by `url`:

```json
{
  "ok": true,
  "ats": "greenhouse",
  "company": "stripe",
  "title": "Account Executive, AI Sales",
  "location": "San Francisco, CA",
  "department": "1650 AI GTM Strategy & Solutions",
  "employmentType": "FullTime",
  "url": "https://stripe.com/jobs/search?gh_jid=7964697",
  "postedAt": "2026-06-05T15:44:04-04:00",
  "description": "Who we are… (plain text, HTML stripped)",
  "salary": "$211.4K – $290.6K • Offers Equity"
}
````

Field availability differs by ATS, so several fields can be `null` even on a successful row:

| Field | Greenhouse | Lever | Ashby |
|---|---|---|---|
| `employmentType` | `null` (not exposed) | ✓ (commitment) | ✓ |
| `salary` | `null` (not exposed) | best-effort (often `null`) | ✓ (structured, may be `null`) |
| `department` | ✓ | ✓ (dept / team) | ✓ (dept / team) |
| `location` / `postedAt` / `url` | ✓ when present, else `null` | ✓ when present, else `null` | ✓ when present, else `null` |

`title` and `company` are always present on a success row. Every other field above is `null` when the board doesn't supply it — this is honest data, not a failed scrape.

Greenhouse job descriptions come HTML-entity-encoded; the actor decodes and strips them to clean plain text.

#### Diagnostic rows (`ok:false`)

When a board has no open postings, uses a wrong/retired slug, or hits a network/blocked error, the actor pushes a single **`ok:false`** diagnostic row instead of job rows, for example:

```json
{ "ok": false, "errorCode": "NO_RESULTS", "error": "The request succeeded but returned no results for this input.", "ats": "greenhouse", "company": "acme", "note": "No open postings for greenhouse:acme." }
```

An `ok:false` row means **that one board** had nothing to return — **not** that the run failed. These rows are **never charged**. Filter on `ok:true` to get only billable job postings. Empty input produces an `ok:false` row with `errorCode: "BAD_INPUT"` instead of crashing the run.

### Billing & empty boards

Billed per job posting returned (`job`), and only for genuine `ok:true` rows. A board with no open postings (or a wrong/retired slug) produces a single `ok:false` diagnostic row explaining why — and is **not** charged. Network/blocked errors and empty/invalid input likewise return a coded `ok:false` diagnostic row instead of failing the whole run, and are never charged.

### Example

```json
{
  "companies": ["greenhouse:stripe", "greenhouse:airbnb", "lever:spotify", "ashby:ramp", "ashby:openai"],
  "maxItems": 0
}
```

# Actor input Schema

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

List of job boards to scrape, each as "ats:token". The ats is greenhouse, lever or ashby; the token is the company's board slug. Examples: "greenhouse:stripe", "greenhouse:airbnb", "lever:spotify", "ashby:ramp", "ashby:openai". Find the slug in a careers-page URL (boards.greenhouse.io/<token>, jobs.lever.co/<company>, jobs.ashbyhq.com/<name>). See the README for more examples and where to find each token.

## `ats` (type: `string`):

Alternative to the list above: pick one ATS and pair it with a single Company below. Ignored when Companies is filled.

## `company` (type: `string`):

The single company's board slug to scrape with the ATS selected above (e.g. "stripe"). Ignored when Companies is filled.

## `maxItems` (type: `integer`):

Cap the number of postings emitted per company. Leave at 0 (or empty) to return every open posting on each board.

## `notionConnector` (type: `string`):

Optional. Write each job as a page into your Notion when the run finishes. Authorize a Notion connector once in Settings → API & Integrations → MCP connectors, then pick it here. Leave empty to skip (default) — results are always saved to the dataset regardless.

## `notionParentId` (type: `string`):

Optional. The Notion data source ID of the database to write into (only used if a Notion connector is set). Leave empty to create the pages privately in your workspace instead.

## `proxyConfiguration` (type: `object`):

Optional. These public ATS APIs have no anti-bot, so no proxy is needed and none is used by default. Only enable a proxy if you hit IP-based rate limits when scraping many boards.

## Actor input object example

```json
{
  "companies": [
    "greenhouse:stripe",
    "lever:spotify",
    "ashby:ramp"
  ],
  "ats": "",
  "maxItems": 0,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

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

Scraped rows are stored in the default dataset (one row per result). Blocked/empty/error runs return a single uncharged diagnostic row instead.

# 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:stripe",
        "lever:spotify",
        "ashby:ramp"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("dami_studio/multi-ats-jobs-scraper").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:stripe",
        "lever:spotify",
        "ashby:ramp",
    ] }

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

# Fetch and print Actor results from the run's dataset (if there are any)
print("💾 Check your data here: https://console.apify.com/storage/datasets/" + run["defaultDatasetId"])
for item in client.dataset(run["defaultDatasetId"]).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:stripe",
    "lever:spotify",
    "ashby:ramp"
  ]
}' |
apify call dami_studio/multi-ats-jobs-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=dami_studio/multi-ats-jobs-scraper",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

```json
{
    "openapi": "3.0.1",
    "info": {
        "title": "Multi-ATS Jobs Scraper (Greenhouse, Lever, Ashby)",
        "description": "Scrape open job listings from the three big ATS job boards — Greenhouse, Lever and Ashby — straight from their public JSON APIs. No key, no login. Pass companies as \"ats:token\" (e.g. greenhouse:stripe) and get every posting normalized to one clean schema.",
        "version": "0.1",
        "x-build-id": "CYf3Rlh0jTwAmbdx3"
    },
    "servers": [
        {
            "url": "https://api.apify.com/v2"
        }
    ],
    "paths": {
        "/acts/dami_studio~multi-ats-jobs-scraper/run-sync-get-dataset-items": {
            "post": {
                "operationId": "run-sync-get-dataset-items-dami_studio-multi-ats-jobs-scraper",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for its completion, and returns Actor's dataset items in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        },
        "/acts/dami_studio~multi-ats-jobs-scraper/runs": {
            "post": {
                "operationId": "runs-sync-dami_studio-multi-ats-jobs-scraper",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor and returns information about the initiated run in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/runsResponseSchema"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/acts/dami_studio~multi-ats-jobs-scraper/run-sync": {
            "post": {
                "operationId": "run-sync-dami_studio-multi-ats-jobs-scraper",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for completion, and returns the OUTPUT from Key-value store in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        }
    },
    "components": {
        "schemas": {
            "inputSchema": {
                "type": "object",
                "properties": {
                    "companies": {
                        "title": "Companies (ats:token)",
                        "type": "array",
                        "description": "List of job boards to scrape, each as \"ats:token\". The ats is greenhouse, lever or ashby; the token is the company's board slug. Examples: \"greenhouse:stripe\", \"greenhouse:airbnb\", \"lever:spotify\", \"ashby:ramp\", \"ashby:openai\". Find the slug in a careers-page URL (boards.greenhouse.io/<token>, jobs.lever.co/<company>, jobs.ashbyhq.com/<name>). See the README for more examples and where to find each token.",
                        "items": {
                            "type": "string"
                        }
                    },
                    "ats": {
                        "title": "ATS (for a single company)",
                        "enum": [
                            "",
                            "greenhouse",
                            "lever",
                            "ashby"
                        ],
                        "type": "string",
                        "description": "Alternative to the list above: pick one ATS and pair it with a single Company below. Ignored when Companies is filled.",
                        "default": ""
                    },
                    "company": {
                        "title": "Company token (for a single company)",
                        "type": "string",
                        "description": "The single company's board slug to scrape with the ATS selected above (e.g. \"stripe\"). Ignored when Companies is filled."
                    },
                    "maxItems": {
                        "title": "Max jobs per company",
                        "minimum": 0,
                        "type": "integer",
                        "description": "Cap the number of postings emitted per company. Leave at 0 (or empty) to return every open posting on each board.",
                        "default": 0
                    },
                    "notionConnector": {
                        "title": "Notion connector (optional)",
                        "type": "string",
                        "description": "Optional. Write each job as a page into your Notion when the run finishes. Authorize a Notion connector once in Settings → API & Integrations → MCP connectors, then pick it here. Leave empty to skip (default) — results are always saved to the dataset regardless."
                    },
                    "notionParentId": {
                        "title": "Notion target data source ID",
                        "type": "string",
                        "description": "Optional. The Notion data source ID of the database to write into (only used if a Notion connector is set). Leave empty to create the pages privately in your workspace instead."
                    },
                    "proxyConfiguration": {
                        "title": "Proxy (optional)",
                        "type": "object",
                        "description": "Optional. These public ATS APIs have no anti-bot, so no proxy is needed and none is used by default. Only enable a proxy if you hit IP-based rate limits when scraping many boards.",
                        "default": {
                            "useApifyProxy": false
                        }
                    }
                }
            },
            "runsResponseSchema": {
                "type": "object",
                "properties": {
                    "data": {
                        "type": "object",
                        "properties": {
                            "id": {
                                "type": "string"
                            },
                            "actId": {
                                "type": "string"
                            },
                            "userId": {
                                "type": "string"
                            },
                            "startedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "finishedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "status": {
                                "type": "string",
                                "example": "READY"
                            },
                            "meta": {
                                "type": "object",
                                "properties": {
                                    "origin": {
                                        "type": "string",
                                        "example": "API"
                                    },
                                    "userAgent": {
                                        "type": "string"
                                    }
                                }
                            },
                            "stats": {
                                "type": "object",
                                "properties": {
                                    "inputBodyLen": {
                                        "type": "integer",
                                        "example": 2000
                                    },
                                    "rebootCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "restartCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "resurrectCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "computeUnits": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "options": {
                                "type": "object",
                                "properties": {
                                    "build": {
                                        "type": "string",
                                        "example": "latest"
                                    },
                                    "timeoutSecs": {
                                        "type": "integer",
                                        "example": 300
                                    },
                                    "memoryMbytes": {
                                        "type": "integer",
                                        "example": 1024
                                    },
                                    "diskMbytes": {
                                        "type": "integer",
                                        "example": 2048
                                    }
                                }
                            },
                            "buildId": {
                                "type": "string"
                            },
                            "defaultKeyValueStoreId": {
                                "type": "string"
                            },
                            "defaultDatasetId": {
                                "type": "string"
                            },
                            "defaultRequestQueueId": {
                                "type": "string"
                            },
                            "buildNumber": {
                                "type": "string",
                                "example": "1.0.0"
                            },
                            "containerUrl": {
                                "type": "string"
                            },
                            "usage": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "integer",
                                        "example": 1
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "usageTotalUsd": {
                                "type": "number",
                                "example": 0.00005
                            },
                            "usageUsd": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "number",
                                        "example": 0.00005
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
```
