# ATS Job Scraper: Greenhouse, Lever & Workday (`olliolli/ats-job-feed`) Actor

Scrape company jobs from 8 ATS platforms. Track new, updated and closed vacancies, filter remote jobs, and export data. Use company domains or job board URLs.

- **URL**: https://apify.com/olliolli/ats-job-feed.md
- **Developed by:** [Tom J](https://apify.com/olliolli) (community)
- **Categories:** Jobs, Business, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $3.00 / 1,000 jobs

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

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

## What's an Apify Actor?

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

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

## How to integrate an Actor?

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

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

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

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

# README

## ATS Job Scraper & Company Hiring Monitor

Extract jobs from **Greenhouse, Lever, Workday, Ashby, SmartRecruiters, Recruitee, Teamtailor and Personio** into one structured dataset. This ATS job scraper reads the public career feeds of companies you choose, then tracks **new, updated and closed vacancies** across recurring runs.

Start with company domains, official job board URLs, or an existing Apify dataset. Filter by job title, country and fully remote work, then export results as JSON, CSV or Excel through Apify. No employer login or source API key is required for the standard routes.

**Pricing:** $3 per 1,000 delivered job rows, plus $0.002 per successfully checked company and a $0.00005 start event at the default 1 GB. In changes mode, unchanged jobs produce no job-row charge. [See examples and billing details](#how-much-does-company-jobs-feed-cost).

Automatic discovery combines website links, a small reverified catalog and a bounded browser fallback. **A supported official board URL is the most predictable starting point.** Some company websites cannot be recognized automatically; check the company statuses in OUTPUT.

### Supported ATS job boards

| ATS | Recommended input | Common use |
|---|---|---|
| Greenhouse | `https://job-boards.greenhouse.io/company` | Greenhouse job listings and hiring changes |
| Lever | `https://jobs.lever.co/company` | Lever vacancies, teams and locations |
| Workday | Employer's `myworkdayjobs.com` board URL | Workday career feeds and paginated vacancies |
| Ashby | `https://jobs.ashbyhq.com/company` | Ashby jobs and structured salary data where published |
| SmartRecruiters | `https://careers.smartrecruiters.com/Company` | Public SmartRecruiters company jobs |
| Recruitee | `https://company.recruitee.com` | Recruitee career-site vacancies |
| Teamtailor | Official company career-site URL | Teamtailor jobs, including identifiable custom sites |
| Personio | `https://company.jobs.personio.de` | Personio vacancies; supported `.com` boards also work |

These URL patterns are illustrative; replace them with the employer's actual public board. Provider coverage does not guarantee that every company using that provider is discoverable or accessible.

### Who is this job scraper for?

- **Recruitment teams:** maintain a target-company vacancy feed and spot newly posted roles.
- **Sales research:** use hiring activity as a company signal alongside your CRM data.
- **Market research:** compare job titles, locations and published salary fields across a chosen company list.
- **Automation workflows:** feed hiring changes into your own dashboards, webhooks or Apify integrations.

### What you can do

- Read public **Greenhouse, Lever, Ashby, SmartRecruiters, Workday, Recruitee, Teamtailor and Personio** job feeds.
- Discover supported ATS links from a company website; override detection with an explicit board URL.
- Export job titles, departments, application links, source dates, locations and published structured salary data where available.
- Run a full snapshot or return only NEW, UPDATED and CLOSED jobs since the previous successful check.
- Filter by title, country, fully remote work and publication date.
- Send one optional webhook containing changes, or use Apify's run-finished integrations.

### How to get company jobs in 3 steps

1. Enter company domains, select an input dataset, or paste official ATS board URLs.
2. Choose `snapshot` for matching jobs, or `changes` with a unique `stateName` for a recurring watchlist.
3. Run the Actor. Download the job dataset and inspect the company-level statuses in OUTPUT.

The sample input intentionally caps each company at three jobs to make your first trial inexpensive. Increase `maxJobsPerCompany` for a fuller feed; a capped scan is explicitly marked partial.

```json
{
  "domains": ["collibra.com", "deliverect.com", "attendi.nl"],
  "mode": "snapshot",
  "maxJobsPerCompany": 3,
  "includeDescription": "text"
}
```

#### Monitor company hiring changes

```json
{
  "boardUrls": ["https://brenger.recruitee.com"],
  "mode": "changes",
  "stateName": "my-company-watchlist",
  "maxJobsPerCompany": 500,
  "includeDescription": "none"
}
```

The first run delivers matching jobs as NEW and establishes a baseline. Later runs deliver changed rows only. Failed checks preserve the previous baseline. Incomplete feeds can report new or updated jobs but **never infer closed jobs**.

#### Read company domains from a dataset

Select an Apify dataset using the resource picker, then set `domainField` to its website field, for example `website` or `company.website`. The Actor scans at most 10,000 source rows and accepts at most 2,000 unique company/board inputs.

### Input

| Field | Default | Meaning |
|---|---|---|
| `domains` | — | Company domains or public career-page URLs; up to 2,000 combined inputs. |
| `boardUrls` | — | Direct official board URLs. A custom Teamtailor site must identify its provider in public HTML. |
| `datasetId`, `domainField` | —, `website` | Selected input dataset and dot-separated website field. |
| `atsOverride` | `[]` | Objects with `domain` and `boardUrl`, or `domain`, `ats` and `token`. Workday needs its board URL. Custom Teamtailor domains accept `ats: teamtailor` and `boardUrl`. |
| `mode` | `snapshot` | `snapshot` or `changes`. |
| `stateName`, `stateStoreId` | — | Named watchlist, or a selected read/write key-value store. Required for changes mode. |
| `titleKeywords` | `[]` | Include titles containing any phrase, case-insensitively. |
| `excludeTitleKeywords` | `[]` | Exclude titles containing any phrase. |
| `countries` | `[]` | ISO-2 country codes, such as BE, NL, DE, FR, GB or US. Unknown countries do not match. |
| `remoteOnly` | `false` | Only explicitly fully remote roles; excludes hybrid and unknown. |
| `postedAfter` | — | ISO date, inclusive. Jobs without a usable source publication date are excluded. |
| `includeDescription` | `text` | `none`, cleaned `text`, or reconstructed safe paragraph `html`. |
| `maxJobsPerCompany` | 500 | 1–5,000; applied before filters. Sample input uses 3. |
| `maxJobsTotal` | 10,000 | 1–100,000 delivered rows; stops cleanly at the limit. |
| `maxCompanySeconds` | 120 | 15–300 seconds per company. Large feeds may be partial before this deadline. |
| `maxRunSeconds` | 1,800 | 30–7,200 seconds for company processing, followed by bounded cleanup/webhook handling. |
| `useCatalog`, `browserFallback` | `true`, `true` | Reverify catalog candidates; inspect dynamic career pages when needed. |
| `maxBrowserCompanies` | 10 | Maximum browser fallbacks per run; requires at least 1 GB. |
| `braveSearchApiKey`, `maxSearchQueries` | —, 10 | Optional paid search provider using your own secret key; capped queries. |
| `webhookUrl` | — | Optional public destination. One POST, no redirects or retries. Keep URLs with secrets out of shared input files. |

### Output

Each job row includes:

- `company`, `companyDomain`, `ats`, `boardUrl`, `jobId`, `title` and `applyUrl`.
- `department`, `team`, `employmentType`, `workplaceType` and `locations[]` with city, region, ISO-2 country and a source label.
- `salary` with min, max, currency and period **only when structured source data supports it**; otherwise null. No salary estimates or AI enrichment.
- `postedAt`, `updatedAt`, `language` and the chosen description field, when available.
- `changeType`, `changedFields`, `firstSeenAt`, `lastSeenAt` and, for closed rows, `closedAt`.

A direct board URL does not establish the employer's corporate website: `companyDomain` is null in that case. A board token can serve as the company label when the source does not publish a company name. Missing dates and locations remain null rather than being invented. Language detection is heuristic.

OUTPUT includes a record for every attempted company: input, detected ATS, board URL, jobs found/matched/delivered, completeness, warnings and status. Statuses include `ok`, `partial`, `no_ats_found`, `unreachable`, `blocked`, `failed`, `duplicate` and `stopped`. A paginated source may not expose a total; then `jobsFound` is a lower bound from retrieved records. OUTPUT also records charged events, unprocessed companies, stop reasons, HTTP request count, connection attempts, recovery events and revision. **A green run does not mean every company was read successfully.**

### How much does Company Jobs Feed cost?

Pay per event: the company check and delivered job rows are separate events. The current Apify pricing table is authoritative. There is no additional automatic dataset-row charge.

| Event | Price (USD) |
|---|---:|
| Successfully checked company feed | $0.002 |
| Delivered job row | $0.003 |
| Standard Actor start, per allocated GB rounded up, minimum one | $0.00005 |

At the default 1,024 MB, 200 successful company checks and 3,000 delivered jobs cost **$9.40005**. A later changes run with those 200 companies and 250 changed rows costs **$1.15005**. A successful check can be charged even when it has no matching jobs or no changes. A clearly marked capped feed also counts as a successful check.

#### Job scraper pricing examples

At the default 1 GB memory:

| Run | Company checks | Delivered rows | Event total (USD) |
|---|---:|---:|---:|
| Small first trial | 1 | 3 | $0.01105 |
| Company watchlist, first snapshot | 200 | 3,000 | $9.40005 |
| Later watchlist run with changes | 200 | 250 | $1.15005 |
| Later watchlist run without changes | 200 | 0 | $0.40005 |

These examples assume every listed company check succeeds. A failed or undetected company has no company-check or job event, but the start event still applies. An optional Brave Search subscription is separate and uses your own key. Changes runs need a stable `stateName` and complete enough feeds to infer closed jobs.

#### What you are not charged for

No company-check event for undetected, blocked or unreachable boards, or failed source parsing. No job event for filtered jobs or unchanged jobs in changes mode. Failed company entries appear in OUTPUT, not as paid job rows. The standard start event still applies to failed runs. There must be **no automatic `apify-default-dataset-item` charge** alongside these explicit events.

A company result is saved before charging its check. A job row is saved before its job event is charged. The Actor checks the remaining budget and stops when it cannot afford the next event. Incomplete delivery preserves that company's old watch baseline. Storage, charging and baseline updates are separate operations: after an uncertain billing/storage interruption, inspect OUTPUT before retrying. Retrying an unfinished company can repeat already delivered rows; cross-service exactly-once delivery is not promised.

### Automate & schedule

Create a task with a stable `stateName` and schedule it at your chosen interval. **Never overlap runs sharing a watchlist.** Each baseline is scoped by board, company domain and filter/description settings. Changing those settings creates a separate baseline. Snapshot mode can update a baseline when you provide a state name; without one, it only exports a snapshot.

CLOSED means a previously observed job is absent from a successfully completed source feed. It does not prove that a person was hired. A cap, source error or incomplete JSON-LD scan never triggers closures. Jobs first observed during a partial scan remain tracked for later complete runs.

The optional webhook sends one JSON payload with `changes`, `jobsDelivered`, `stopped` and `revision`. It includes NEW/UPDATED/CLOSED summary rows, capped at 1,000 entries with `changesCapped`; use the dataset for the full result. Delivery failure is reported without retrying or discarding the dataset. Use an Apify run-finished webhook if you want to hand downstream systems the dataset ID directly.

### Integrate with any app

The Apify API requires your Apify token; source websites do not require a separate API key. Optional Brave Search discovery requires your own Brave key and may incur separate search-provider charges.

Python:

```python
from apify_client import ApifyClient
client = ApifyClient("YOUR_APIFY_TOKEN")
run = client.actor("olliolli/ats-job-feed").call(run_input={
    "domains": ["attendi.nl"], "maxJobsPerCompany": 100
})
for job in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(job["title"], job["applyUrl"])
```

JavaScript:

```javascript
import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('olliolli/ats-job-feed').call({
  domains: ['attendi.nl'], maxJobsPerCompany: 100
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items);
```

### MCP

Once this Actor is available to your account, add it through Apify's MCP server to an MCP-compatible client. Use the same inputs and inspect both the dataset and OUTPUT. MCP does not bypass source access restrictions.

### Good to know

- Discovery reads at most six public HTML pages per company and respects robots.txt. It deduplicates redirected/trailing-slash pages and prioritizes vacancy lists and details over career stories, including external career sites explicitly linked by the company, and can inspect one bounded sitemap. If needed, it tries the hostname-derived board name and at most one explicit company name from the homepage metadata on Greenhouse, Lever and Ashby (at most six board-feed probes, at most three in parallel, plus one content request for small Greenhouse boards (up to 50 jobs), or at most three individual job descriptions for larger boards per candidate name). A guessed board is accepted only when at least two distinct jobs link back to the employer domain through canonical job URLs or corporate/legal/career links, including dedicated jobs/careers subdomains. Greenhouse verification reads lightweight job metadata first; large boards need only a few individual descriptions. Name similarity alone is insufficient. OUTPUT records the discovery method, evidence URL and cache use. These checks reduce mistaken matches but cannot guarantee perfect attribution. A bounded browser fallback can inspect dynamic pages, but hidden boards and unsupported systems may still be missed; provide the official board URL or an override when known.
- Positive ATS detections are cached for seven days. A cached board returning 404/410 is evicted for the next run. A board that still responds but is outdated can require an override until cache expiry.
- Requests use a direct public connection, with HTTP feed requests paced to at most two per second per host and five in flight. Browser asset requests use Chromium scheduling and a separate 100-request cap per company. Company processing is sequential. No residential proxies, browser evasion or login sessions are used.
- Conditional ETag/Last-Modified requests are used for supported single-document feeds when a complete normalized cache exists. Raw responses are not stored. Paginated/detail feeds are fetched afresh.
- Feed completeness is based on what the public source exposes. SmartRecruiters and Workday can need an extra request per job; large companies may hit the time/job cap. Raise the limits cautiously and inspect `complete`.
- JSON-LD fallback reads up to five same-host job/career pages, excludes expired listings when a validThrough date is present, and is always marked incomplete. It never emits CLOSED rows.
- No CAPTCHA solving, employer-account credentials, imported cookies, applicant APIs, recruiter directory extraction, LinkedIn/Indeed scraping or unlimited IP rotation. Rate limits and access blocks stop that host for the run.
- Recruitee documents a future authentication change for its Careers Site API on **10 February 2027**. This version uses the currently public endpoint. If it becomes restricted, the Actor reports blocked; it does not obtain or bypass credentials. Re-verify this adapter before that date.
- HTTP(S) only, ports 80/443, public DNS/IPs only. Redirects are revalidated and DNS is pinned to public addresses. Response sizes are bounded; an oversized response is a reported failure.

### Privacy

Only whitelisted public job fields are copied. Recruiter, hiring-manager, creator and applicant fields are excluded. Descriptions remove email/phone patterns and contact-bearing paragraphs; contact sections are omitted. HTML is reconstructed as safe paragraphs, without scripts, forms, tracking images or links. Cleaning is conservative and may omit useful text; it is not a general-purpose anonymization guarantee for arbitrary source prose. Set `includeDescription: none` when you only need job metadata.

Raw ATS responses, cookies, headers and raw exception messages are not stored or logged. Company inputs and application URLs are part of your results; do not include private URLs or secrets. State stores contain cleaned job snapshots and public board/cache information until you delete them. The optional webhook transmits the selected change summaries to your supplied public destination.

### FAQ

#### Can I scrape Greenhouse, Lever and Workday jobs together?

Yes. Put their official board URLs in one `boardUrls` list. Results share a common schema, so you can filter and export them together. Workday requires the employer's full board URL, including its site name.

#### Does this replace a global job search API?

It provides a company-specific job feed, not a searchable worldwide index. You choose the employers; the Actor reads their supported public sources. It does not scrape LinkedIn or Indeed.

#### Can I schedule daily or weekly job monitoring?

Yes. Save a task with `mode: changes` and a unique `stateName`, then create an Apify schedule for that task. Avoid overlapping runs against the same state. The first successful scan establishes the baseline; later scans return matching changes.

#### Can I search all jobs worldwide by keyword?

No. Supply the companies or boards you want to follow. Title keywords filter those companies' jobs; this Actor has no independent global index.

#### Why does my company show no_ats_found?

The configured discovery routes did not identify a supported public feed within their limits. The company may use another ATS, hide its board behind a dynamic application, block requests or require more time. Try its official board URL or `atsOverride`. This status does not mean the company has no jobs.

#### Why is a company marked partial?

A job/time limit was reached, or the source was a limited JSON-LD scan. Delivered rows remain useful, but the feed cannot establish that missing jobs closed. Increase limits when appropriate.

#### Does the first changes run charge for every matching job?

It delivers current matching jobs as NEW, so the job event applies once per delivered row. Subsequent unchanged jobs are not delivered or charged, although the successful company check still applies.

#### Can filters create false closed-job alerts?

The Actor compares the unfiltered source snapshot before deciding which change rows match your filters. A title moving outside your filter is not treated as a source closure. Changing filter settings establishes a separate baseline.

#### Can I get salaries, remote jobs and multiple locations?

Yes when the source supplies usable fields. Unknown salary/country/date fields remain null. Fully remote is distinct from hybrid. The Actor does not estimate salaries or infer remote status from every mention in a description.

#### Can I use my CRM or a Google Maps dataset?

Yes. Select its dataset and website field. Only company websites are read; the Actor does not need or copy CRM contact people.

### Disclaimer

Independent tool, not affiliated with Greenhouse, Lever, Ashby, SmartRecruiters, Workday, Recruitee, Teamtailor, Personio or employers. A screening/research aid, not a certified account of hiring activity. Respect source terms and your rights to process the content.

### Need help?

Open an Apify issue with the run ID, public board URL, relevant settings and safe OUTPUT reason. Do not share tokens, private datasets or personal information.

### Automatic ATS recognition: catalog, browser and optional search

The Actor first tries a small bundled catalog of previously verified public boards. Each catalog candidate must again pass the two-job employer-domain check; entries expire after 30 days. This is a limited convenience directory, not a comprehensive company database. Set `useCatalog: false` to measure discovery without this assistance. Cached successful mappings last seven days.

If normal website discovery fails, `browserFallback: true` opens at most two public career pages in a fresh anonymous browser context. It can inspect rendered links and up to eight first-party JSON responses. The browser accepts explicit supported ATS URLs found on an official career page or in its first-party JSON responses. The career page must have been discovered through the company website or a same-domain career path. This uses the same first-party link evidence as ordinary HTML discovery and supports all eight ATS providers. Guessed catalog/search candidates still require two-job verification. No forms are submitted. Images, fonts, media, WebSockets and service workers are blocked. Access blocks and robots exclusions are respected.

The browser has a 25-second limit and 100-request cap per company, with at most `maxBrowserCompanies` (default 10) fallbacks per run. Use at least 1,024 MB. Low memory or insufficient remaining company time skips the fallback. Company discovery has a maximum 65-second budget plus a bounded catalog check, within `maxCompanySeconds`; feed retrieval also needs time. The default 120 seconds is recommended.

An optional `braveSearchApiKey` enables one search request per unresolved company, up to `maxSearchQueries` (default 10) per run. The company domain is sent to Brave Search. Search ranking and snippets are never accepted as proof: supported board candidates need two distinct employer-domain links. Search errors disable further queries for the run. The key is secret input, is not forwarded across redirects, and is never written to OUTPUT. No key or paid search subscription is bundled.

OUTPUT company records include `discoveryDiagnostics` for attempted catalog, search and browser routes. `discoveryMethod` distinguishes `verified-catalog`, `verified-search`, `company-browser-link` and normal website discovery. A catalog-assisted success rate must not be described as discovery accuracy on unseen companies. None of these routes guarantees universal recognition; an official board URL remains the most predictable input.

# Actor input Schema

## `domains` (type: `array`):

Company domains or public career URLs. Up to 2,000 inputs.

## `boardUrls` (type: `array`):

Optional public board URLs; skips company discovery.

## `datasetId` (type: `string`):

Read company websites from another Actor.

## `domainField` (type: `string`):

Dot-separated dataset field.

## `mode` (type: `string`):

Snapshot delivers all matching jobs. Changes emits new, updated and closed jobs.

## `stateName` (type: `string`):

Required for changes mode. Reuse the same name; never overlap runs.

## `stateStoreId` (type: `string`):

Optional selected store instead of a named store.

## `atsOverride` (type: `array`):

Objects with domain and boardUrl, or domain, ats and token.

## `includeDescription` (type: `string`):

Contact-bearing paragraphs removed. HTML is reconstructed safe paragraph markup.

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

Only explicitly fully remote roles; hybrid is excluded.

## `postedAfter` (type: `string`):

YYYY-MM-DD. Roles without a source publication date are excluded.

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

Limit applies before filters. Incomplete feeds never emit closed jobs.

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

Stop after this many delivered rows; incomplete company state is preserved.

## `maxRunSeconds` (type: `integer`):

Stop cleanly and list unchecked companies.

## `maxCompanySeconds` (type: `integer`):

Includes discovery, source reads and delivery.

## `webhookUrl` (type: `string`):

Optional public HTTPS receiver; one POST with NEW/UPDATED/CLOSED rows after the run. No redirects or retries.

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

Keep titles containing any of these phrases.

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

Remove titles containing any of these phrases.

## `countries` (type: `array`):

ISO-2 country codes; unknown countries do not match.

## `useCatalog` (type: `boolean`):

Recheck a small public domain-to-board catalog before website discovery.

## `browserFallback` (type: `boolean`):

Read dynamic public career pages when HTTP discovery fails. Requires 1024 MB and enough company time; no CAPTCHA solving.

## `maxBrowserCompanies` (type: `integer`):

Cost cap for browser discovery.

## `maxSearchQueries` (type: `integer`):

Limit optional Brave Search requests.

## `braveSearchApiKey` (type: `string`):

Your own Brave Search key. Search candidates must pass employer-domain verification. External search charges are separate.

## Actor input object example

```json
{
  "domains": [
    "collibra.com",
    "deliverect.com",
    "attendi.nl"
  ],
  "domainField": "website",
  "mode": "snapshot",
  "includeDescription": "text",
  "remoteOnly": false,
  "maxJobsPerCompany": 3,
  "maxJobsTotal": 10000,
  "maxRunSeconds": 1800,
  "maxCompanySeconds": 120,
  "useCatalog": true,
  "browserFallback": true,
  "maxBrowserCompanies": 10,
  "maxSearchQueries": 10
}
```

# Actor output Schema

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

No description

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

No description

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "domains": [
        "collibra.com",
        "deliverect.com",
        "attendi.nl"
    ],
    "maxJobsPerCompany": 3
};

// Run the Actor and wait for it to finish
const run = await client.actor("olliolli/ats-job-feed").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 = {
    "domains": [
        "collibra.com",
        "deliverect.com",
        "attendi.nl",
    ],
    "maxJobsPerCompany": 3,
}

# Run the Actor and wait for it to finish
run = client.actor("olliolli/ats-job-feed").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 '{
  "domains": [
    "collibra.com",
    "deliverect.com",
    "attendi.nl"
  ],
  "maxJobsPerCompany": 3
}' |
apify call olliolli/ats-job-feed --silent --output-dataset

```

## MCP server setup

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

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/24C2Ri4tKkqrFCRfn/builds/D6ltiuLQf02Nfb2un/openapi.json
