# Company Jobs Finder: jobs by company name, Workday + 13 ATS (`kohnschnee/ats-jobs-finder`) Actor

Type a company name, get every open job from its career site: Workday, Greenhouse, Lever, Ashby, SmartRecruiters, Workable and 8 more. One format, salary where stated, hiring snapshot and map. Names are enough; a careers URL is exact. Honest counts, robots.txt respected.

- **URL**: https://apify.com/kohnschnee/ats-jobs-finder.md
- **Developed by:** [Stefan Affentranger](https://apify.com/kohnschnee) (community)
- **Categories:** Jobs
- **Security:** Limited permissions
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.50 / 1,000 job returneds

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

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

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## Company Jobs Finder

**Type a company name, get every open job it has posted: from its career site on Workday, Greenhouse, Lever, Ashby, SmartRecruiters, Workable, Recruitee, Personio, Teamtailor, Pinpoint, Breezy, BambooHR, Rippling or Prospective (jobs.ch group, Switzerland), in one table, with salary where stated, a map and a one-page hiring report. Run it once, or let it tell you only what is new each week.** $2.00 per 1,000 jobs on the Free plan.

This is a company-first tool, not a job search engine: you name the employers, it reads their own career sites directly (no aggregator, no stale copies, honest counts). Fourteen systems behind one input field: paste a name or domain and the Actor finds the board on any of them (Prospective has numeric ids: give its careers URL or `prospective:<id>`). Workday, the system of most large employers (Roche, Nestlé, NVIDIA, Adobe …), is resolved from a bundled directory of public Workday sites and the employer's own robots.txt, verified live; sites with more than 2,000 jobs are read past Workday's list cap. The same Workday engine is also available on its own as [Workday Jobs Finder](https://apify.com/kohnschnee/workday-jobs-finder).

### Quick start (no code)

1. In **Which companies?** paste names, websites or careers links, one per line: `stripe`, `notion.so`, `https://jobs.lever.co/palantir`.
2. Click **Start**. A run of 10 companies takes about half a minute. Want the full job texts or pay parsed from them? Tick **Include description** first.
3. On the run page: the **Output** tab is the table (tabs *Jobs*, *Salary*, *Locations*, *All fields*; download as Excel, CSV or JSON). The **Storage → Key-value store** tab holds `report.html` (one-page hiring report, with a plain-words line per company: found, not found and why, complete or not), `results-map.html` (map) and `SUMMARY` (the same as JSON).
4. Want it weekly? Tick **Only new since my last run**, then **Schedule** the Actor and pick a destination under **Integrations** (Google Sheets, Slack, e-mail, Telegram …).

The example tasks on this page are pre-filled; copy one and change the names.

### Which companies can it find?

| The company's jobs page URL contains … | Result |
|---|---|
| `myworkdayjobs.com`, `myworkdaysite.com` (Workday) | found by name or URL; big sites read past the 2,000 cap; robots.txt respected |
| `greenhouse.io`, `lever.co`, `ashbyhq.com`, `smartrecruiters.com`, `workable.com`, `recruitee.com`, `personio.de`, `teamtailor.com`, `pinpointhq.com`, `breezy.hr`, `bamboohr.com`, `rippling.com` | found by name or URL |
| `prospective.ch` (jobs.ch group, Swiss public employers) | by careers URL or `prospective:<id>` |
| something else (SuccessFactors, iCIMS, Taleo, Oracle, own site) | `not_found` with a hint; not covered yet |

Not sure? Paste the name: the SUMMARY tells you whether a board was found, on which system, and which alternatives exist under the same name. A name that equals a Workday tenant is checked there first (one request); otherwise the twelve ATS are asked, then Workday's directory and the tenant's robots.txt.

### Fields

One row per job posting.

| Field | Notes |
|---|---|
| `company`, `ats`, `boardSlug`, `input` | `company` is the name the board reports (Workday: the name you typed), else a readable form of the slug; never a URL. `ats` is one of the fourteen systems (`workday` included); `boardSlug` is `tenant/site` on Workday |
| `jobId`, `title`, `url`, `applyUrl` | always filled (`applyUrl` on SmartRecruiters only with descriptions) |
| `department`, `team` | as published |
| `location`, `city`, `country`, `countryName`, `isRemote`, `isRemoteSource`, `workplaceType` | `country` is ISO-2 (`CH`), `countryName` the English name; `isRemote` from the system's flag or the word "remote" in the location, `isRemoteSource` = `ats` or `location text`. Greenhouse and Personio publish no country. |
| `employmentType`, `seniority`, `schedule`, `experienceLevel` | where published |
| `salaryMin`, `salaryMax`, `salaryCurrency`, `salaryPeriod`, `salaryText`, `salarySource`, `salaryRanges` | `salarySource` = `structured` (Ashby, Lever, Recruitee publish a field) or `text` (a pay range stated in the description; `salaryText` is the exact statement, `salaryRanges` how many location tiers were merged into min/max). `salaryPeriod` = `year`, `month`, `week`, `day` or `hour`. Currencies recognised: USD, CAD, GBP, EUR, CHF, AUD, SGD, INR. Structured wins over text. `null` when neither exists. |
| `publishedAt`, `updatedAt` | ISO 8601 UTC. Greenhouse: `first_published`, else `updated_at` (then both equal). Workable: date without time. |
| `description` | plain text, only with *Include description* |
| `firstSeen` | delta mode: the date you first received this posting |
| `tenant`, `site`, `postedText`, `startDate`, `remoteType`, `additionalLocations`, `hiringOrganization` | Workday only. `postedText` is the site's wording (`Posted 3 Days Ago`), from which `publishedAt` is derived (`30+ Days Ago` stays `null`); with *Include description* the exact `startDate`, country, remote type, further locations and the hiring entity are read per job |
| `scrapedAt` | when this run read the board |

Example row:

```json
{"company": "Ramp", "ats": "ashby", "boardSlug": "ramp", "jobId": "0f1c…", "title": "Software Engineer, Backend",
 "department": "Engineering", "location": "New York", "city": "New York", "country": "US", "countryName": "United States",
 "isRemote": true, "isRemoteSource": "ats", "employmentType": "FullTime",
 "salaryMin": 180000, "salaryMax": 240000, "salaryCurrency": "USD", "salaryPeriod": "year", "salarySource": "structured",
 "publishedAt": "2026-10-28T14:02:11+00:00", "url": "https://jobs.ashbyhq.com/ramp/0f1c…", "scrapedAt": "2026-11-02T16:30:00+00:00"}
```

Example `SUMMARY` entry (key-value store):

```json
{"input": "ramp", "status": "found", "ats": "ashby", "boardSlug": "ramp", "companyNameOnBoard": null, "matchedBy": "name",
 "jobsOnBoard": 172, "jobsMatched": 172, "jobsReturned": 172,
 "alsoFoundOn": [{"ats": "greenhouse", "boardSlug": "ramp", "jobsOnBoard": 1}],
 "newJobs": 4, "closedJobs": 2, "unchangedJobs": 168, "closed": [{"jobId": "…", "title": "…", "url": "…", "firstSeen": "2026-10-20", "closedOn": "2026-11-02"}],
 "snapshot": {"jobs": 172, "departmentsTop": [["Engineering", 61], ["Sales", 40]], "remoteShare": 0.9, "withSalaryShare": 0.95,
              "newestPostedAt": "2026-11-01", "postedLast7Days": 4, "countriesTop": [["United States", 160]], "citiesTop": [["New York, US", 120]]}}
```

`status` is one of `found`, `partial` (Workday: read, but a slice beyond the 2,000 cap stayed out of reach; `error` says how many), `empty_board` (board exists, no jobs), `not_found`, `robots_disallowed` (the employer's robots.txt forbids reading its Workday site for everyone: honoured, nothing read, nothing charged), `duplicate_of` (same board given twice), `error` (no system could answer: down or rate-limiting; `error` holds the HTTP code), `stopped_cost_limit` / `skipped_cost_limit`. Workday entries also carry `tenant`, `site`, `resolvedBy` (directory or robots.txt), `alternatives` (other live sites under the name) and `listedTotal`. When one system rate-limits while the others answer "no board", the entry stays `not_found` and lists that system under `unchecked`, so a rate limit on one vendor never masquerades as an outage. A host that answers HTTP 429 is slowed down for the rest of the run (interval doubles up to 8 s, Retry-After honoured). Every non-`found` entry carries a `hint` in plain words.

### Input

- **Which companies?** names, website domains or careers URLs. A URL is exact. A name is matched to board slugs (`Zürich Insurance AG` tries `zurichinsuranceag`, `zurich-insurance-ag`, `zurichinsurance`, `zurich`). A few companies use a slug nobody would guess (`doordashusa`): use the URL then. The same board given twice is read once.
- **Job system**: leave on *auto*. `workday` asks Workday only.
- **Search text (Workday)**: Workday's own search box; narrows a 10,000-job site before reading. Ignored on the other systems.
- **Narrow down** (all optional): *Title keywords*, *Location keywords* (two letters like `CH` mean the country), *Remote only*, *Only jobs stating pay*, *Posted within days*, *Max jobs per company* (applied after the filters).
- **Monitor**: *Only new since my last run* and *List name* (see below).
- **Output**: *Include description* (off by default: full text as a column, also enables salary from text, turned on automatically with *Only jobs stating pay*; on SmartRecruiters one request per job), *All boards* (deliver every board found under a name), *Map view*.

### Monitor: only new since my last run

One mechanism, one switch. Tick **Only new since my last run**, schedule the Actor, choose a destination under **Integrations**. From the second run on you receive only postings that were not in your previous run, and the SUMMARY shows per company `newJobs`, `unchangedJobs`, `closedJobs` and the list `closed` (title, link, first seen, closed on). Only new postings are charged: a daily watch over 50 companies costs cents.

- The memory is a key-value store **in your account** named `ats-jobs-finder-state-<list name>`. Nothing is kept on our side. Delete it to start over.
- The first run returns everything (`firstRun: true`).
- Filters still apply; a new posting that does not match them is remembered but not delivered.
- If a run stops at your cost cap, the undelivered new postings arrive in the next run.
- *Posted within days* is a date filter, not a memory: it returns what was published recently, including postings you already have. Use it when you do not want a memory; use the monitor when you do.

### Hiring report and map

Every run writes `report.html` (KPIs, jobs per company, department, city and country, postings per day over 28 days, distribution of stated base salaries; printable; no external library) and, with *Map view* on, `results-map.html` (jobs by city, click for titles and links; places resolved locally against GeoNames, CC BY 4.0, no external geocoder). Both are in the run's key-value store and can be forwarded as files.

### Pricing and duration

Pay per job returned; companies not found and filtered-out jobs are free; platform usage is included. Per 1,000 jobs by Apify plan: **Free and Bronze $2.00 · Silver $1.80 · Gold, Platinum and Diamond $1.50.**

| Run | Jobs | Cost on Free | Duration |
|---|---|---|---|
| One scale-up (`notion`) | ~150 | $0.30 | 5 s |
| 10 US tech companies with pay ranges (`includeDescription` on) | ~3,400 | $6.80 | 40 s |
| 50 companies, weekly monitor | ~400 new per week | $0.80 per week | 1 min |
| `https://careers.smartrecruiters.com/BoschGroup`, no descriptions | ~5,000 | $10.00 | 1 min |
| the same with descriptions (one request per job) | ~5,000 | $10.00 | ~85 min, delivered in blocks |

A cost cap: in the Console under *Run options → Maximum cost per run*; in the API the run parameter `maxTotalChargeUsd`. The Actor stops cleanly and `jobsReturned` matches what you were charged.

### For developers and AI agents

Python, with a $1 cap:

```python
from apify_client import ApifyClient
client = ApifyClient("<YOUR_API_TOKEN>")
run = client.actor("kohnschnee/ats-jobs-finder").call(
    run_input={"companies": ["anthropic", "https://jobs.lever.co/palantir", "notion"], "includeDescription": True},
    max_total_charge_usd=1.0,
)
jobs = list(client.dataset(run["defaultDatasetId"]).iterate_items())
store = client.key_value_store(run["defaultKeyValueStoreId"])
summary = store.get_record("SUMMARY")["value"]          # list of dicts, see example above
report_html = store.get_record("report.html")["value"]  # str
map_html = store.get_record("results-map.html")["value"]
```

JavaScript:

```javascript
import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: '<YOUR_API_TOKEN>' });
const run = await client.actor('kohnschnee/ats-jobs-finder').call({ companies: ['stripe', 'figma'] }, { maxTotalChargeUsd: 1 });
const { items } = await client.dataset(run.defaultDatasetId).listItems();
```

n8n / Make / Zapier: the Apify node runs the Actor with this input and hands over the dataset; a second node can fetch the key-value store records `SUMMARY`, `report.html`, `results-map.html`. AI agents: every Store Actor is callable through Apify's MCP server; the input schema is self-describing.

Key-value store keys: `SUMMARY` (per company), `SNAPSHOT` (overall, with map and report statistics), `report.html`, `results-map.html`. Dataset views: `overview`, `salary`, `places`, `full`.

### Limits, honestly

- Companies on other systems (SuccessFactors, iCIMS, Taleo, Oracle, own sites) are `not_found`.
- Workday: a name is found when the tenant slug resembles the name (`roche`, `cvshealth`); a slug nobody would guess (`sonyglobal`) needs the URL. Measured on 40 pre-registered names: 28 of 37 resolved. Sites under robots.txt `Disallow` are reported, not read. Lists are read 20 jobs per request at one request per second: 1,250 jobs take about a minute; `searchText` and *Max jobs per company* cut that.
- One request per second per system (Lever asks for exactly that). SmartRecruiters descriptions cost one request per job.
- A board that changes while it is read can differ from its live count by a job or two.
- Workable lists one row per location of the same job (same `jobId`, different `location`); that is how the company posted it.
- Text-derived salary is only as good as the posting's wording; `salaryText` lets you check it. The parser was verified on 60 blind-labelled descriptions (52 of 52 ranges exact, 0 false hits on 60 descriptions without pay).
- The map places jobs by the location text; "Remote" and multi-place texts are counted beside the map.

### Legal and fair use

This Actor uses the public job-board endpoints of Greenhouse, Lever, Ashby, SmartRecruiters (Posting API), Workable (widget API), Recruitee, Personio, Teamtailor (JSON Feed, documented as RSS), Pinpoint (documented `postings.json`), Breezy, BambooHR and Rippling (the endpoints their own career pages load), Prospective (`ohws.prospective.ch`, robots.txt allows everything) and Workday career sites (the JSON their own pages load; the tenant's robots.txt is read first and a `Disallow` is honoured), which exist so that a company's open jobs can be displayed elsewhere. One request per second per system, identified, no login, no cookies, no personal data. SmartRecruiters' API host has a general robots disallow for crawlers; the Posting API is nevertheless the documented public interface for this purpose. Workable's robots file states `ai-train=no`: use the data for reading, matching and analysis, not for training models. Respect the posting companies' terms when you reuse their postings.

### FAQ

**A company is hiring but comes back `not_found`.** It uses a system this Actor does not cover, or a board slug that differs from its name. Open its careers page, click a job and paste that URL: any page of a Workday, Greenhouse, Lever … site works. If the status is `error` with an HTTP code, the system was down or rate-limiting; run again later.

**I got a different company than I meant.** Names are shared. Check `companyNameOnBoard` and `alsoFoundOn` in the SUMMARY, or pass the careers URL.

**Does it find salary for every job?** No. `salarySource` says `structured`, `text` or `null`. Tick *Only jobs stating pay* to keep only those.

**How do I get only new jobs each week?** *Only new since my last run* plus a schedule. *Posted within days* is a date filter without memory.

**Where are the report and the map?** Run page → Storage → Key-value store → `report.html`, `results-map.html`.

**Is this legal?** It reads documented public APIs at a polite rate, without login or personal data. See *Legal and fair use*.

**Something is wrong?** Open an issue on this page with the input that failed.

### Changelog

- **1.5 (3 Nov 2026)**: one input field for everything, Workday included. Named *Company Jobs Finder*. A company on Workday is found and read (directory of public tenants + the employer's robots.txt, verified live; past the 2,000 cap; robots `Disallow` honoured; `searchText`; exact dates and pay with *Include description*) instead of getting a hint to another Actor. New statuses `partial` and `robots_disallowed`, Workday fields in the dataset. Measured need: of 115 Swiss company names, 6 of the 85 not found on any ATS run Workday (Zühlke, CRISPR, Acronis, Medela, DocMorris, Zur Rose), and Roche had landed in the wrong Actor.
- **1.4 (3 Nov 2026)**: rate limits handled per host: a system answering HTTP 429 is paused and slowed down for the whole run (Retry-After honoured, interval doubling up to 8 s) instead of being retried per request; companies for which only that system could not be checked stay `not_found` with `unchecked: ["workable"]` rather than `error` (found on 3 Nov with 115 names in one run: Workable throttled from company ~60 on and 45 entries were wrongly `error`).
- **1.2 (2 Nov 2026)**: delta mode with closed-postings list, `report.html`, *Only jobs stating pay*, input form in sections with plain-language help, hints in SUMMARY, README rebuilt after an independent usability review.
- **1.3 (3 Nov 2026)**: six more systems: Teamtailor, Pinpoint, Breezy, BambooHR (description, date and pay text via detail), Rippling (one row per job, all locations merged) and Prospective (Swiss employers via jobs.ch group; `workload` = Pensum); a company on Workday gets a hint with its Workday site; pay parser also reads `168,000 USD – 264,500 USD`; URL parser no longer fails on malformed input.
- **1.1 (2 Nov 2026)**: salary from text, `allBoards`, hiring snapshot, map, ISO country + `countryName`, unified `isRemote`, better name matching, Personio offices, four dataset views, tiered pricing; fixes from an independent code review (numeric salaries, Workable demo accounts filtered, SmartRecruiters in blocks, outages reported as `error`, duplicate boards read once).
- **1.0 (2 Nov 2026)**: first release.

### Tested

Offline tests on recorded real responses for all fourteen systems (75 tests, plus property-based tests that found three defects before any user did), a blind-labelled salary set, a live check against 27 companies (counts equal to the source boards, random job URLs reachable) before each release, an independent code review and an independent usability review.

# Actor input Schema

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

Examples: `stripe`, `notion.so`, `Roche`, `https://jobs.lever.co/palantir`, `https://nvidia.wd5.myworkdayjobs.com/NVIDIAExternalCareerSite`. A careers URL is exact; a name is matched to the board and the SUMMARY tells you which board was used.

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

Automatically detect (recommended). Pick one system only if you know it and want to skip detection; `workday` asks Workday only.

## `searchText` (type: `string`):

Workday's own search box, e.g. `data scientist`: narrows a Workday site before reading, so a 10,000-job employer costs seconds, not minutes. Ignored on the other systems (use Title keywords there).

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

Keep jobs whose title contains any of these words, e.g. `engineer`, `sales`, `praktikum`. Not case-sensitive.

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

Keep jobs whose place contains any of these, e.g. `Zurich`, `Germany`, `Remote`. Two letters like `CH` or `US` mean the country code.

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

Only jobs marked remote by the system or by the word 'remote' in the location.

## `withSalaryOnly` (type: `boolean`):

Keep only jobs with a salary figure (from the system or stated in the text; the text needs 'Include description' on).

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

Only jobs published in the last N days, e.g. 7 for the last week. Jobs without a date are left out.

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

Stop after this many jobs per company (after the filters). 0 = all.

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

Remembers what you already received, in a key-value store in your account named `ats-jobs-finder-state-<state key>`.

## `stateKey` (type: `string`):

Only change this if you monitor several different company lists, e.g. `clients-dach` and `startups-us`. Each list has its own memory.

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

Full job text as plain text; also enables salary parsed from the text. Turned on automatically with 'Only jobs stating pay'. On SmartRecruiters this costs one request per job (a 5,000-job board takes ~85 minutes instead of 1).

## `allBoards` (type: `boolean`):

If a company name exists on several systems, deliver all of them instead of only the largest board.

## `mapView` (type: `boolean`):

Create `results-map.html` in the key-value store: the returned jobs by city on a zoomable map.

## Actor input object example

```json
{
  "companies": [
    "anthropic",
    "Roche",
    "notion"
  ],
  "ats": "auto",
  "remoteOnly": false,
  "withSalaryOnly": false,
  "maxJobsPerCompany": 0,
  "onlyNewSinceLastRun": false,
  "stateKey": "default",
  "includeDescription": false,
  "allBoards": false,
  "mapView": true
}
```

# Actor output Schema

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

One row per job posting (JSON; add ?format=csv for CSV).

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

Per input company: board found, jobs on board, matched, returned, status and reason.

## `map` (type: `string`):

Zoomable map of the returned jobs by city.

## `snapshot` (type: `string`):

Jobs, departments, remote share, salary share, posting dates, top places.

## `report` (type: `string`):

One-page HTML report of the returned jobs.

# 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": [
        "anthropic",
        "Roche",
        "notion"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("kohnschnee/ats-jobs-finder").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": [
        "anthropic",
        "Roche",
        "notion",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("kohnschnee/ats-jobs-finder").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": [
    "anthropic",
    "Roche",
    "notion"
  ]
}' |
apify call kohnschnee/ats-jobs-finder --silent --output-dataset

```

## MCP server setup

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

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/O5dod2I6Q3UDk9kMR/builds/1FXTx8eTc7nLcloRS/openapi.json
