# ATS Jobs Scraper — 7 Platforms + 5,000-Company Directory (`myexcelsolutions/ats-jobs-scraper-greenhouse-lever-ashby`) Actor

5,000 validated company boards, seven public ATS platforms, normalized jobs, and only-new-jobs delta mode for $0.001 per job.

- **URL**: https://apify.com/myexcelsolutions/ats-jobs-scraper-greenhouse-lever-ashby.md
- **Developed by:** [My Excel Solutions](https://apify.com/myexcelsolutions) (community)
- **Categories:** Jobs, Developer tools, 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 items

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 web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
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/docs.md):

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

In Python projects, use official [Python client library](https://docs.apify.com/api/client/python/docs.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/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

## ATS Jobs Scraper — 7 Platforms + 5,000-Company Directory

**5,000 validated company job boards built in — run it against the whole directory, filter by platform or keyword, or bring your own slugs. Seven ATS platforms, one normalized schema, $0.001 per job, and an only-new-jobs delta mode.**

ATS Jobs Scraper is a directory-first Apify Actor for collecting public job postings from Greenhouse, Lever, Ashby, Workable, SmartRecruiters, Recruitee, and Personio. It is designed for job aggregators, career-search tools, recruiting research, internal talent intelligence, and scheduled data exports that need reliable source records at a predictable price.

The built-in directory is the main difference. You do not need to arrive with thousands of company slugs or maintain a separate board-discovery database. You can run all 5,000 validated boards, select one or more ATS platforms, apply a title keyword, request explicitly remote roles, or combine directory mode with your own board URLs. For a narrow workflow, pass one company. For a market-wide feed, schedule the directory with delta mode and pay only when new postings appear.

There is no AI enrichment, email discovery, company enrichment, or inferred salary layer. The Actor reads intentionally public career-site endpoints, validates each platform's response tolerantly, and maps source fields into one deterministic contract. Missing data remains `null`.

### What you get

- A committed directory of exactly 5,000 company job boards, discovered through Common Crawl and validated against live public ATS endpoints.
- Seven ATS integrations behind a stable output schema.
- Direct input as `{ platform, slug }` objects or pasted career-board URLs.
- Case-insensitive title filtering and an explicit-remote filter applied before billing.
- Delta mode that establishes a baseline and then emits and charges only unseen jobs.
- Within-run deduplication on `(platform, companySlug, jobId)`.
- Polite fetching: no more than five boards in parallel, a static identifying User-Agent, bounded retry/backoff, and non-fatal invalid-slug handling.
- Pay-per-event pricing of **$0.001 per returned unique job**, plus Apify's $0.0005 Actor-start event.

### Supported platforms and normalized fields

| Platform | Public source | Job identity and title | Location / remote | Employment / compensation | Posted date |
|---|---|---|---|---|---|
| Greenhouse | Board API | Native `id`, `title` | Free-text location; no reliable remote flag, so `remote: null` | Departments; published pay-transparency ranges when exposed | `updated_at` |
| Lever | Postings API, global and EU | Native `id`, `text` | Category location, country, `workplaceType` | Commitment and published `salaryRange` | Epoch `createdAt` |
| Ashby | Posting API | Stable job URL segment, `title` | Location, postal city/country, `isRemote` | Employment type and published salary component | `publishedAt` |
| Workable | Public widget API | `shortcode`, `title` | City/state/country, `telecommuting` | Employment type; compensation not exposed | `published_on` |
| SmartRecruiters | Company postings API | Native `id`, `name` | Structured city/region/country and remote flag | Department and employment labels; compensation not exposed | `releasedDate` |
| Recruitee | Careers Site Offers API | Native `id`, `title` | Location or locations and source remote flag | Department and employment type when present; compensation not exposed | `published_at`, then `created_at` |
| Personio | Public XML syndication feed | Native `id`, `name` | Office; remote is not reliably structured, so `remote: null` | Department and employment type; compensation always `null` | `createdAt` |

Null-over-guessing is a contract, not a limitation to hide. The Actor does not infer remote work from “work from home” in a title, split a free-text location into a guessed city, treat a bonus as base salary, or manufacture an employment type. If a platform does not expose a dependable field, the normalized field is `null`.

### Quick start: bring your own boards

Pass board objects, supported URLs, or both. URL auto-detection extracts the correct company identifier.

```json
{
  "boards": [
    { "platform": "greenhouse", "slug": "openai" },
    "https://jobs.lever.co/netflix",
    "https://jobs.ashbyhq.com/linear",
    "https://jobs.recruitee.com/o/account-manager",
    "https://personio.jobs.personio.de/job/1834171"
  ],
  "keywordFilter": "engineer",
  "remoteOnly": true,
  "maxJobsPerBoard": 100
}
````

Direct boards and seed-directory boards are deduplicated before fetching. A malformed URL is rejected at input validation. A syntactically valid but nonexistent company identifier produces an `invalid_slug` board outcome and does not crash the rest of the run.

### Quick start: use the 5,000-board directory

Run the directory without maintaining a slug list:

```json
{
  "useSeedDirectory": true,
  "seedFilterPlatforms": ["greenhouse", "lever", "recruitee", "personio"],
  "keywordFilter": "data",
  "remoteOnly": false,
  "onlyNewSinceLastRun": true
}
```

The committed seven-platform distribution is:

| Platform | Validated company boards |
|---|---:|
| Greenhouse | 907 |
| Lever | 500 |
| Ashby | 1,250 |
| Workable | 700 |
| SmartRecruiters | 1,043 |
| Recruitee | 300 |
| Personio | 300 |
| **Total** | **5,000** |

Directory entries are not assumed valid merely because a URL appeared in a web index. The build process extracts candidate hostnames or path slugs, requests each platform's public endpoint at a maximum of two request starts per second, checks the expected JSON or XML shape, and only commits successful boards. A resumable local progress cache prevents unnecessary repeat probes.

Use `seedFilterPlatforms` to control both runtime and selection identity. Running only Personio and Recruitee is a different delta baseline from running all seven platforms.

### Input reference

| Field | Type | Default | Meaning |
|---|---|---|---|
| `boards` | array | `[]` | `{ platform, slug }` objects or supported ATS board URLs; required unless directory mode is enabled |
| `useSeedDirectory` | boolean | `false` | Include the bundled 5,000-board directory |
| `seedFilterPlatforms` | array | all seven | Restrict directory mode to selected ATS platforms |
| `keywordFilter` | string | — | Case-insensitive substring match against job title |
| `remoteOnly` | boolean | `false` | Keep only jobs whose source explicitly marks them remote |
| `maxJobsPerBoard` | integer | `0` | Cap returned jobs per board; zero is unlimited; in delta mode this caps new jobs after old jobs are removed |
| `onlyNewSinceLastRun` | boolean | `false` | Establish a selection-specific baseline, then emit and charge only unseen jobs |
| `deltaStateReset` | boolean | `false` | Delete saved state for the current selection and make the next delta result a fresh baseline |

### Stable output schema

One dataset item is returned per unique `(platform, companySlug, jobId)`. This example is generated byte-for-byte from the recorded Workable fixture used by the normalization tests:

```json
{
  "platform": "workable",
  "companySlug": "acme",
  "jobId": "WK101",
  "title": "Data Analyst",
  "department": "Analytics",
  "location": {
    "raw": "Boston, Massachusetts, United States",
    "city": "Boston",
    "country": "United States"
  },
  "remote": true,
  "employmentType": "full_time",
  "compensation": null,
  "postedAt": "2026-07-02T00:00:00.000Z",
  "applyUrl": "https://apply.workable.com/acme/j/WK101/apply/",
  "sourceUrl": "https://apply.workable.com/acme/j/WK101/",
  "fetchedAt": "2026-07-21T12:00:00.000Z"
}
```

Filters, normalization, and deduplication run before publication. Only published records reach `Actor.pushData(job, 'job-item')`, so a filtered or duplicate record is not billed.

### Only-new-jobs delta mode

Set `onlyNewSinceLastRun: true` for recurring collection. The first successful run for a selection is its baseline: every matching unique job is returned and charged, then the job identities are saved. Later runs remove saved identities before the publisher, so only new records are written and charged.

Selection state is isolated in the caller's named Apify key-value store, `ats-jobs-delta-state`. Its key is a SHA-256 hash of the canonical board selection, directory platform filters, title keyword, and remote-only setting. Board order and platform-filter order do not matter. Changing a board, keyword, remote setting, directory mode, or directory platform set intentionally creates a new baseline. The run log says when this happens.

The Phase 1.5 fixture-scale verification cycle is concrete:

| Run | Source fixture | Returned jobs | Charged `job-item` events |
|---|---|---:|---:|
| Baseline | jobs 1, 2, 3 | 3 | 3 |
| Next scheduled run | old jobs 1, 2, 3 plus new jobs 4, 5 | 2 | 2 |
| Unchanged run | jobs 1 through 5 | 0 | 0 |

For a practical cost example, suppose a weekly scheduled run covers 1,000 boards. The baseline returns 20,000 matching jobs and costs $20 in job-item events. If the following week has 650 new matching postings, that run returns 650 items and costs $0.65, rather than charging again for the 20,000 old postings. The Actor-start event still applies to every run.

State is saved only after publication. If the process crashes after pushing records but before its final state save, those records can be returned and charged again on the next run. This is the deliberate safe failure direction: duplicate delivery after a rare interrupted save is preferable to permanently losing new jobs. Downstream consumers that require exactly-once processing should also key on `(platform, companySlug, jobId)`.

The saved seen-set is capped at the most recent **500,000 job hashes**. If a selection exceeds that bound, the Actor logs a warning and drops the oldest hashes. Very old jobs could then reappear if an ATS republishes or retains them indefinitely. Use narrower platform or keyword selections if this matters. Set `deltaStateReset: true` together with delta mode when you intentionally want to repay for and rebuild a baseline.

### Pricing, free evaluation, and graceful limits

The primary pay-per-event event is `job-item` at **$0.001 per returned unique job**, equivalent to $1 per 1,000 job records. The synthetic `apify-actor-start` event is $0.0005. Filtering and delta removal happen before charging.

Apify Free-plan users can evaluate up to **3 boards and 50 jobs per run**. These limits compose with delta mode: old jobs are removed first, and up to 50 genuinely new records are published. A PPE budget limit also stops publication gracefully. The Actor checks `eventChargeLimitReached`, records an accurate status message, and exits successfully instead of relying on the SDK to stop it.

### Integrate through MCP

When the Apify MCP server is connected to an AI client, call its Actor-running tool with the Actor ID and ordinary input. Tool names vary slightly by MCP client; the payload is equivalent to:

```json
{
  "tool": "call-actor",
  "arguments": {
    "actorId": "ats-jobs-scraper-greenhouse-lever-ashby",
    "input": {
      "boards": ["https://jobs.lever.co/netflix"],
      "keywordFilter": "engineer",
      "onlyNewSinceLastRun": true
    }
  }
}
```

Read the completed run's default dataset for normalized jobs. The same PPE price, delta state, free limits, and run budget apply whether a run begins through MCP, Apify Console, the REST API, or a schedule.

### Schedule with an Apify Task

1. Open the published Actor in Apify Console and choose **Create task**.
2. Save a stable input. For a recurring feed, enable `onlyNewSinceLastRun`; keep filters fixed so every scheduled run uses the same selection identity.
3. Open **Schedules**, create a weekly or daily cron schedule, and attach the saved Task.
4. Set a sensible maximum run charge. Remember that the first run is a full baseline.
5. Use the Task's dataset or a webhook to hand the new records to your database, automation, or notification layer.

If you edit a Task's board list or filters, expect one new baseline. If you only change schedule timing, the delta identity is unchanged.

### n8n workflow

There are two simple patterns. For polling, use a Schedule Trigger, then an HTTP Request node that starts the saved Apify Task through the Apify API. Wait for completion, request the run's default dataset items, and feed each item into your database, spreadsheet, Slack, or email nodes. Store the Apify token in n8n credentials, not in workflow text.

For push delivery, configure an Apify Actor-run-succeeded webhook aimed at an n8n Webhook node. The webhook payload identifies the completed run. Use an authenticated HTTP Request node to fetch `defaultDatasetId/items`, then branch on fields such as `platform`, `remote`, or `department`. Delta mode keeps this workflow quiet: an unchanged run produces no job items.

### Make workflow

Create a scheduled scenario with **HTTP → Make a request** to start the saved Apify Task. Add a sleep/poll loop or use an Apify completion webhook to resume the scenario. Fetch the completed default dataset, iterate the returned array, and map normalized fields into Airtable, Google Sheets, a CRM, or a notification module. Keep the scheduling input stable and enable delta mode so Make operations are spent on new postings instead of processing the same historical board repeatedly.

Neither n8n nor Make needs platform-specific parsing. Every route consumes the same normalized schema.

### Honest product comparison

| Product | Choose it when | Coverage and differentiation | Published result price | AI enrichment |
|---|---|---|---:|---|
| **ATS Jobs Scraper** | You want a budget source feed, a built-in validated company directory, and delta runs | 7 public ATS platforms; 5,000 validated boards; deterministic normalized output | **$0.001/job** | No |
| [fantastic-jobs](https://apify.com/fantastic-jobs) | You need much broader ATS coverage or enriched job intelligence | 54-platform positioning and AI-enriched output | $0.004–$0.012/job | Yes |

This Actor is not a substitute for fantastic-jobs when enrichment or broad long-tail ATS coverage is the requirement. Conversely, users who only need normalized public source records should not have model costs baked into every item.

#### Zero AI by design

Zero AI is a reliability and pricing choice. Normalization is deterministic, the same input shape maps to the same fields, and no model can hallucinate a salary, seniority, department, or location that the ATS did not publish. There are no token costs hidden inside the $0.001 event price and no model outage in the fetch path. Source records can still contain employer-written mistakes, but the Actor does not amplify them through inference.

### Reliability and source etiquette

The Actor uses the static User-Agent `ats-jobs-actor/1.0`, processes no more than five boards concurrently, times requests out, and retries only network errors, HTTP 429, and HTTP 5xx with bounded backoff. A 404 is treated as invalid board data. One malformed job is skipped with a warning while valid siblings continue. Personio XML and the six JSON APIs are parsed through platform-specific tolerant schemas.

The endpoints are public because they power employer career sites and syndication feeds. The Actor does not bypass authentication, scrape applicant data, or access private recruiting systems.

### Rebuild the directory

The committed directory is ready to use. Maintainers can refresh it with:

```sh
npm run seed:build
```

Target one platform while preserving all enforced minimums:

```sh
npm run seed:build -- --platform recruitee --min-platform 300 --collection-count 100 --candidate-cap 10000
npm run seed:build -- --platform personio --min-platform 300 --collection-count 100 --candidate-cap 10000
```

The builder exits nonzero when it cannot meet the relevant minimum. Current enforced minimums are Greenhouse 900, Lever 500, Ashby 900, Workable 700, SmartRecruiters 900, Recruitee 300, and Personio 300. Fixed-size rebalancing reserves those entries before filling the remaining directory slots.

### Local development

Node.js 22 is required.

```sh
npm install
npm run check
npm run smoke:fixtures
npm run build
```

Run locally with the Apify CLI:

```sh
apify run -i '{"boards":[{"platform":"greenhouse","slug":"openai"}]}'
```

Set `ACTOR_TEST_PAY_PER_EVENT=true` for local PPE testing. After authenticating, use `apify push` to deploy.

### Relevant API searches

Greenhouse job board API · Lever postings API · Ashby job board API · Workable jobs API · SmartRecruiters postings API · Recruitee offers API · Personio XML jobs feed · ATS job scraper · scrape Greenhouse jobs · normalized job postings API · only new jobs scraper

# Actor input Schema

## `boards` (type: `array`):

Board objects ({ platform, slug }) or bare ATS board URLs. Required unless Use seed directory is enabled.

## `useSeedDirectory` (type: `boolean`):

Run across the bundled validated company-board directory.

## `seedFilterPlatforms` (type: `array`):

When using the seed directory, include only these platforms.

## `keywordFilter` (type: `string`):

Case-insensitive substring match against the job title.

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

Return only jobs whose ATS explicitly marks them as remote.

## `maxJobsPerBoard` (type: `integer`):

Zero means no per-board cap.

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

Establish a baseline for this board/filter selection, then return and charge only jobs not seen in earlier successful runs.

## `deltaStateReset` (type: `boolean`):

Discard the saved state for this selection. Use with Only new jobs to create a fresh baseline.

## Actor input object example

```json
{
  "boards": [
    {
      "platform": "greenhouse",
      "slug": "openai"
    },
    "https://jobs.lever.co/netflix",
    "https://jobs.ashbyhq.com/linear"
  ],
  "useSeedDirectory": false,
  "remoteOnly": false,
  "maxJobsPerBoard": 0,
  "onlyNewSinceLastRun": false,
  "deltaStateReset": false
}
```

# Actor output Schema

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

Unique, post-filter job records charged as job-item events.

# 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 = {
    "boards": [
        {
            "platform": "greenhouse",
            "slug": "openai"
        },
        "https://jobs.lever.co/netflix",
        "https://jobs.ashbyhq.com/linear"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("myexcelsolutions/ats-jobs-scraper-greenhouse-lever-ashby").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 = { "boards": [
        {
            "platform": "greenhouse",
            "slug": "openai",
        },
        "https://jobs.lever.co/netflix",
        "https://jobs.ashbyhq.com/linear",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("myexcelsolutions/ats-jobs-scraper-greenhouse-lever-ashby").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 '{
  "boards": [
    {
      "platform": "greenhouse",
      "slug": "openai"
    },
    "https://jobs.lever.co/netflix",
    "https://jobs.ashbyhq.com/linear"
  ]
}' |
apify call myexcelsolutions/ats-jobs-scraper-greenhouse-lever-ashby --silent --output-dataset

```

## MCP server setup

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

```

## OpenAPI specification

```json
{
    "openapi": "3.0.1",
    "info": {
        "title": "ATS Jobs Scraper — 7 Platforms + 5,000-Company Directory",
        "description": "5,000 validated company boards, seven public ATS platforms, normalized jobs, and only-new-jobs delta mode for $0.001 per job.",
        "version": "0.1",
        "x-build-id": "6m4B5VmAwUnq3sUE4"
    },
    "servers": [
        {
            "url": "https://api.apify.com/v2"
        }
    ],
    "paths": {
        "/acts/myexcelsolutions~ats-jobs-scraper-greenhouse-lever-ashby/run-sync-get-dataset-items": {
            "post": {
                "operationId": "run-sync-get-dataset-items-myexcelsolutions-ats-jobs-scraper-greenhouse-lever-ashby",
                "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/myexcelsolutions~ats-jobs-scraper-greenhouse-lever-ashby/runs": {
            "post": {
                "operationId": "runs-sync-myexcelsolutions-ats-jobs-scraper-greenhouse-lever-ashby",
                "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/myexcelsolutions~ats-jobs-scraper-greenhouse-lever-ashby/run-sync": {
            "post": {
                "operationId": "run-sync-myexcelsolutions-ats-jobs-scraper-greenhouse-lever-ashby",
                "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": {
                    "boards": {
                        "title": "Boards",
                        "type": "array",
                        "description": "Board objects ({ platform, slug }) or bare ATS board URLs. Required unless Use seed directory is enabled.",
                        "default": []
                    },
                    "useSeedDirectory": {
                        "title": "Use seed directory",
                        "type": "boolean",
                        "description": "Run across the bundled validated company-board directory.",
                        "default": false
                    },
                    "seedFilterPlatforms": {
                        "title": "Seed platforms",
                        "uniqueItems": true,
                        "type": "array",
                        "description": "When using the seed directory, include only these platforms.",
                        "items": {
                            "type": "string",
                            "enum": [
                                "greenhouse",
                                "lever",
                                "ashby",
                                "workable",
                                "smartrecruiters",
                                "recruitee",
                                "personio"
                            ],
                            "enumTitles": [
                                "Greenhouse",
                                "Lever",
                                "Ashby",
                                "Workable",
                                "SmartRecruiters",
                                "Recruitee",
                                "Personio"
                            ]
                        }
                    },
                    "keywordFilter": {
                        "title": "Title keyword",
                        "type": "string",
                        "description": "Case-insensitive substring match against the job title."
                    },
                    "remoteOnly": {
                        "title": "Remote jobs only",
                        "type": "boolean",
                        "description": "Return only jobs whose ATS explicitly marks them as remote.",
                        "default": false
                    },
                    "maxJobsPerBoard": {
                        "title": "Maximum jobs per board",
                        "minimum": 0,
                        "type": "integer",
                        "description": "Zero means no per-board cap.",
                        "default": 0
                    },
                    "onlyNewSinceLastRun": {
                        "title": "Only new jobs since last run",
                        "type": "boolean",
                        "description": "Establish a baseline for this board/filter selection, then return and charge only jobs not seen in earlier successful runs.",
                        "default": false
                    },
                    "deltaStateReset": {
                        "title": "Reset delta state",
                        "type": "boolean",
                        "description": "Discard the saved state for this selection. Use with Only new jobs to create a fresh baseline.",
                        "default": 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
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
```
