# Jobs Feed API — Workday, Greenhouse, Lever & Ashby Jobs (`factpipe/ats-jobs-feed`) Actor

Job listings API: 800,000+ live job postings from 19,000+ companies' Workday, Greenhouse, Lever, Ashby, Personio, Teamtailor, Workable and Recruitee boards. Salary, seniority, remote filters. $5 per 1,000 jobs.

- **URL**: https://apify.com/factpipe/ats-jobs-feed.md
- **Developed by:** [Neo B](https://apify.com/factpipe) (community)
- **Categories:** Jobs, Lead generation
- **Features:** Limited permissions
- **Stats:** 225 total users, 156 monthly users, 99.9% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $3.50 / 1,000 job results

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

## Jobs Feed API — Workday, Greenhouse, Lever & Ashby Jobs

**Search live openings from thousands of companies' official Greenhouse, Lever, Ashby, Workable and Recruitee job boards. Deduplicated JSON with salary, remote and location filters. $3 per 1,000 jobs.**

| Title | Company | Locations | Workplace | Salary min |
|---|---|---|---|---|
| Software Engineer | Whitespace | Alexandria, Virginia, United States | remote | — |
| Staff Software Engineer, GI | Hinge Health | San Francisco-HQ | hybrid | 197000 |
| Senior Software Engineer (Fundraising) — Remote | GiveDirectly | Remote | remote | — |

*Real output from the “Remote software engineer jobs (last 7 days)” example, run on September 27, 2026.*

**Try a ready-made example:** [Remote software engineer jobs (last 7 days)](https://apify.com/factpipe/ats-jobs-feed/examples/remote-software-engineer-jobs) · [AI & machine learning engineer jobs](https://apify.com/factpipe/ats-jobs-feed/examples/ai-machine-learning-engineer-jobs) · [Product manager jobs in the United States](https://apify.com/factpipe/ats-jobs-feed/examples/product-manager-jobs-united-states) · [Data analyst jobs in Europe](https://apify.com/factpipe/ats-jobs-feed/examples/data-analyst-jobs-europe)

Search **live job openings from 10,000+ companies** in one feed. The jobs come from the **official public job-board APIs** of Greenhouse, Lever, Ashby, Workable and Recruitee. Filter by keyword, location, country, remote, company, department, employment type and posting date. Keyword searches are **ranked by relevance** (title matches first), and you get flat, deduplicated JSON with salary ranges wherever the employer publishes them. **$3 per 1,000 jobs**, and you pay only for jobs delivered.

### Quick start

1. Click **Start** with the prefilled input: `keywords: ["engineer"]`, `remote: "remote_only"`, `postedWithinDays: 7`, `maxResults: 20`. The run takes well under a minute.
2. You get the 20 most relevant remote engineering jobs posted in the last week (jobs with "engineer" in the title first, newest first among equals), each with company, locations, country codes, apply link and (where published) salary.
3. That first run costs at most **$0.06** (20 jobs × $0.003), which fits in Apify's free monthly credit. Then change the filters or schedule the run with `sinceLastRun: true` to get a daily feed of new jobs only.

### What you get

One flat record per job opening:

```json
{
  "job_id": "ashby:ramp:34413f8d-26bf-4bbc-8ade-eb309a0e2245",
  "title": "Security Engineer, Cloud",
  "company_name": "Ramp",
  "company_board": "ramp",
  "ats": "ashby",
  "department": "Engineering",
  "team": "Backend",
  "employment_type": "full_time",
  "seniority": null,
  "workplace_type": "hybrid",
  "locations": ["New York, NY (HQ)", "Remote (Canada)", "Remote (US)", "Miami, FL"],
  "country_codes": ["CA", "US"],
  "remote": true,
  "salary_min": 211400,
  "salary_max": 290600,
  "salary_currency": "USD",
  "salary_period": "year",
  "salary_source": "structured",
  "years_experience_min": 5,
  "visa_sponsorship": null,
  "posted_at": "2026-04-07T17:12:35.753Z",
  "updated_at": null,
  "apply_url": "https://jobs.ashbyhq.com/ramp/34413f8d-26bf-4bbc-8ade-eb309a0e2245/application",
  "job_url": "https://jobs.ashbyhq.com/ramp/34413f8d-26bf-4bbc-8ade-eb309a0e2245",
  "description_text": "ABOUT RAMP\n\nRamp is building the smart infrastructure for finance teams…",
  "description_snippet": "ABOUT RAMP Ramp is building the smart infrastructure for finance teams, embedded in the transaction flow of every dollar a business spends…",
  "description_status": "included",
  "duplicate_sources": [],
  "match_score": 100,
  "matched_in": "title",
  "source_url": "https://api.ashbyhq.com/posting-api/job-board/ramp?includeCompensation=true",
  "fetched_at": "2026-09-19T03:00:00.000Z"
}
```

- `workplace_type` is one of `remote`, `hybrid`, `onsite` or `unknown`. We never guess: when an ATS has no workplace field (Greenhouse), the value comes from the location text ("Remote, Canada"), and otherwise it is `unknown`.
- Salary fields come from the ATS's structured compensation (Ashby, Lever, Recruitee, Personio) or, when it has none, from pay stated in the description text (`salary_source` says which). They are never estimated.
- `country_codes` are ISO 3166 alpha-2 codes. They come from the ATS's own country fields where available, and are otherwise inferred from the location text on a best-effort basis.
- `duplicate_sources` lists the other `job_id`s of the same opening. Example: a company that still has an old board live after switching ATS. Each opening is delivered and charged once.
- `description_text` is fetched **live from the company's ATS** for each delivered job (see below). `description_status` is `included`, `not_requested` (when `includeDescription: false`) or `unavailable` (the ATS could not be reached, or the posting has no text).
- `match_score` (0–100) and `matched_in` (`title`, `department` or `description`) show why a job matched your keywords. Both are `null` when you search without keywords.
- **No personal data.** Recruiter and hiring-manager fields are never copied. In descriptions, e-mail addresses, phone numbers and names in contact lines ("Questions? Call Jane on …") are replaced with `[… redacted]`.

**Enrichment (deterministic, no AI).** Every job gets `seniority` (`intern`, `entry`, `mid`, `senior`, `lead`, `manager`, `director`, `executive`), read from the title by fixed rules, including common German, French, Spanish, Dutch and Portuguese markers. It is `null` when the title has no level marker ("Software Engineer"): no guessing. When the run reads the job's full description (`includeDescription`, the default), the text also gives `years_experience_min` ("3+ years", "3–5 years" → 3), `visa_sponsorship` (`true` when offered, `false` when ruled out, `null` when not mentioned) and, for jobs without structured pay, the pay stated in the text (`salary_source: "description"`; the ATS's own pay fields are `structured` and never overwritten). Without the description these three stay `null`. Personio publishes a level and the years of experience as fields: they fill `seniority` when the title has no level word and `years_experience_min` even without the description. Same input, same output: no language model, no estimates.

### Use cases

- **Job boards and aggregators**: a clean, deduplicated feed of direct-from-employer jobs with apply links, refreshed daily.
- **Sales and lead generation**: see who is hiring for which team and where. A hiring burst signals budget. Filter by department ("sales", "security") or by company list.
- **Recruiting and talent intelligence**: track competitors' openings, salary ranges and remote policy.
- **Job alerts and newsletters**: schedule with `sinceLastRun` to get only the jobs posted since the previous run.
- **AI agents and RAG**: small input, flat deterministic JSON, and full plain-text descriptions (up to 20,000 characters).

### Input

| Field | Type | Notes |
|---|---|---|
| `keywords` | string\[] | Case-insensitive. A title matches at a word start ("engineer" matches "Engineering Manager"). In the description, every word of the keyword must appear |
| `keywordMatch` | `any` | `all` | Default `any` |
| `keywordScope` | `title` | `title_and_description` | Default `title_and_description`: title, department, team and the **first ~1,500 characters** of the description |
| `excludeKeywords` | string\[] | Drops jobs whose **title** contains any of them |
| `locations` | string\[] | City/state/country/region text as written in the posting, or an ISO country code (`US`, `DE`, `UK`) |
| `remote` | `any` | `remote_only` | `onsite_only` | `onsite_only` excludes jobs marked remote |
| `postedWithinDays` | integer | First published within the last N days |
| `companies` | string\[] | Company names (`Datadog`) or board tokens (`datadog`, `greenhouse:datadog`) |
| `ats` | string\[] | Any of `greenhouse`, `lever`, `ashby`, `workable`, `recruitee`, `workday`, `personio`, `teamtailor` |
| `departments` | string\[] | Substring match on department or team |
| `employmentTypes` | string\[] | `full_time`, `part_time`, `contract`, `temporary`, `internship`, `other` |
| `seniority` | string\[] | `intern`, `entry`, `mid`, `senior`, `lead`, `manager`, `director`, `executive`, read from the job title. Jobs whose title has no level marker are excluded when this is set |
| `maxResults` | integer | Default 100. With keywords, the most relevant jobs come first; without keywords, the newest |
| `maxPerCompany` | integer | Optional cap on jobs from any one company (prefill 3), so a single employer posting many near-identical roles can't fill your results |
| `includeDescription` | boolean | Default `true`. Fetches the full plain-text description (max 20,000 chars) live from the ATS for every delivered job. A 300-char snippet is always included. Set `false` for the fastest runs |
| `sinceLastRun` | boolean | Incremental feed: returns only jobs not delivered by an earlier run with the same filters |
| `companyUrls` | string\[] | **Live mode**: board URLs (`https://job-boards.greenhouse.io/gitlab`, `https://jobs.lever.co/acme`, `https://jobs.ashbyhq.com/acme`, `https://apply.workable.com/acme`, `https://acme.recruitee.com`, `https://acme.wd5.myworkdayjobs.com/External`, `https://acme.jobs.personio.de`, `https://acme.teamtailor.com`; a Teamtailor custom domain as `teamtailor:careers.acme.com`) or `ats:token` strings. These boards are fetched live, so you can use companies that are not in the index yet |

**Ranking.** With keywords, every matching job gets a `match_score`:

| Where the keywords matched | `match_score` |
|---|---|
| Every keyword in the title | 100 |
| Some keywords in the title | 60–70 |
| Department or team | 40–50 |
| Description only | 20–30 |

More keywords matched means a higher score inside each band. Among equal scores, the newest posting comes first. So a search for `["security engineer"]` returns jobs titled "Security Engineer" before jobs that only mention security engineering in their description, however new those are. The Actor ranks across the whole index, not just the newest postings, before it delivers the top `maxResults`. Without keywords, results come newest first.

**How it works.** By default the Actor searches a compact, prebuilt search index of every board in our directory, rebuilt daily from the ATS APIs. The whole index is about 53 MB compressed. It holds every searchable field, plus the distinct words of each posting's first ~1,500 description characters. The Actor downloads only the parts that can match your `ats`, `companies` and date filters.

**Descriptions.** For every job it is about to deliver, the Actor fetches the description from the ATS. A single API call per company returns all of that company's jobs, so 100 jobs from 20 companies cost 20 calls. Lever and Workable calls are spaced out to respect their limits. A side benefit: a job the employer closed after the nightly build is detected and skipped, not delivered or charged. If a company's ATS can't be reached, the job is still delivered with `description_status: "unavailable"`.

**Live mode.** With `companyUrls` it fetches those boards live instead of using the index.

**Fallback.** If the index is ever unreachable, the run falls back to live-fetching a small set of large boards, so a scheduled run never fails empty.

**Incremental mode.** With `sinceLastRun: true`, the Actor keeps a small cursor per filter combination in a named key-value store in your Apify account (`factpipe-ats-jobs-feed-state`). Jobs already delivered are skipped and not charged. A second run straight after the first returns 0 jobs and costs $0. Note that the cursor follows each job's posting date, so a board added to the index later only contributes jobs posted after your last run.

### Pricing (pay per event)

| Event | Price | Meaning |
|---|---|---|
| `job-result` | **$3.00 per 1,000** ($0.003 each) | One job record delivered, with or without its description. **No start fee. Runs with no matches, jobs skipped by `sinceLastRun`, jobs found closed at delivery time, and failed boards are never charged.** |

Example: 10,000 jobs cost **$30**. Set a maximum charge per run in Apify, and the Actor stops cleanly when it is reached.

**Price change on November 6, 2026:** `job-result` becomes **$5.00 per 1,000** ($4.50 / $4.00 / $3.50 on Starter / Scale / Business plans), reflecting the added Workday, Personio and Teamtailor coverage and the new enrichment fields. Platform usage stays included.

### Coverage

Search-index build of 2026-10-10:

| ATS | Jobs in index |
|---|---|
| Workday | 385,425 |
| Greenhouse | 148,443 |
| Workable | 79,741 |
| Ashby | 54,458 |
| Lever | 51,038 |
| Recruitee | 12,819 |
| **Total** | **731,924** from **15,339** company job boards (after collapsing 53,189 duplicate listings) |

Workday sites contribute their newest 500 jobs each to the index; read a Workday site live (`companyUrls`) for all of its jobs.

**Personio and Teamtailor** (added 2026-10-14): 2,397 Personio and 1,956 Teamtailor career sites with open jobs (22,853 and 39,070 listed jobs) are in the directory and join the search index with its nightly build. Until a platform's first build, a search limited to it reads a few built-in boards live; any Personio or Teamtailor board also works in live mode (`companyUrls`).

About 15% of indexed jobs carry a structured salary range.

Coverage grows as the directory is refreshed. Every board in the index had at least one open job when it was last checked. If a company you need is missing, pass its board URL in `companyUrls`.

### Sources and terms

Only official, public, unauthenticated job-board APIs and feeds that the ATS vendors publish for displaying and syndicating open jobs. No career-site HTML scraping, no logins, no LinkedIn or Indeed.

| ATS | API | Reuse terms |
|---|---|---|
| Greenhouse | [Job Board API](https://developers.greenhouse.io/job-board.html) | "Job Board data is publicly available"; no authentication for GET |
| Lever | [Postings API](https://github.com/lever/postings-api) | Published postings "are publicly viewable" and "may be scraped by third parties"; we respect its 1 request/s crawl delay |
| Ashby | [Public Job Posting API](https://developers.ashbyhq.com/docs/public-job-posting-api) | Public, unauthenticated posting API |
| Workable | [Public jobs endpoint](https://help.workable.com/hc/en-us/articles/115012771647) | Documented public endpoint for published jobs; robots.txt allows crawling |
| Recruitee | [Careers Site API](https://docs.recruitee.com/reference/offers) | Public API returning published offers |
| Workday | Public career sites (`<company>.<wdN>.myworkdayjobs.com/<site>`) | Not a vendor-documented API: the job list and job pages each site loads for its visitors. Each host's robots.txt is checked first (career sites allow `/<site>/`); about 4 requests/s across all Workday hosts |
| Personio | [XML job feed](https://developer.personio.de/docs/retrieving-open-job-positions) (`<company>.jobs.personio.de/xml`) | Published by Personio for job portals and company sites. Each host's robots.txt is read first and only a text/plain file allowing `/xml` and `/job/` counts; a company that disallows it is never read |
| Teamtailor | Career-site RSS feed (`<company>.teamtailor.com/jobs.rss`) | The jobs feed each career site links for its visitors (`rel="alternate"`), no Teamtailor API or login. robots.txt checked per host first (career sites disallow only `/app/`, `/messages/` and similar) |

SmartRecruiters is deliberately **not** included, because its API host's robots.txt disallows automated access. BambooHR is **not** included either: its Terms of Service forbid using any robot or spider to monitor or copy content from the service, which hosts its customers' careers pages.

### factpipe Jobs & Hiring Data

These Actors search the same daily index of 730,000+ open jobs from 15,000+ company job boards:

- [Jobs Feed API](https://apify.com/factpipe/ats-jobs-feed) (this Actor): every job, every filter, ranked by relevance.
- [Remote Jobs API](https://apify.com/factpipe/remote-jobs-feed): remote and work-from-home jobs only, filtered by region or time zone.
- [Greenhouse, Lever, Ashby & Workday Jobs Scraper](https://apify.com/factpipe/ats-jobs-scraper): pick the applicant tracking systems and companies you want.
- [Companies Hiring](https://apify.com/factpipe/companies-hiring): one row per company that is hiring for a role, as sales leads or market research.
- [Greenhouse Jobs API](https://apify.com/factpipe/greenhouse-jobs-api): every Greenhouse job board in one search.
- [Lever Jobs API](https://apify.com/factpipe/lever-jobs-api): every Lever job board, with salary where published.
- [Ashby Jobs API](https://apify.com/factpipe/ashby-jobs-api): every Ashby job board: startup and AI jobs, with salary where published.
- [Workday Jobs API](https://apify.com/factpipe/workday-jobs-api): thousands of Workday career sites of large employers (NVIDIA, Salesforce, Adobe…), with full descriptions.

### FAQ

**How is this different from LinkedIn or Indeed scrapers?**
We don't scrape any job site. Every job comes from the employer's own applicant tracking system, through the official public API that also powers the company's careers page. That makes the data first-party and current: a job is gone from the feed once the employer closes it. It also carries the direct apply link, and there are no reposts, recruiter spam or login walls. There is no ban risk and no proxy cost, which is why it costs $3 per 1,000 jobs.

**How fresh is the data?**
The search index is rebuilt daily. With `includeDescription` on (the default), every delivered job is re-checked live against the employer's ATS during your run, and closed jobs are dropped. `fetched_at` is when the index read that board, and `posted_at` is the employer's own publish date.

**Does keyword search cover the whole description?**
It covers the title, department, team and the first ~1,500 characters of each description, which is usually the role summary and the first requirements. Words that appear in most of one company's postings (its "About us" boilerplate) are matched per company. Use `keywordScope: "title"` for strict title searches.

**Which companies are covered?**
About 15,000 company job boards with open jobs on Greenhouse, Lever, Ashby, Workable, Recruitee and Workday, plus the Personio and Teamtailor career sites added in October 2026 (see Coverage). They were discovered from Common Crawl's public URL index and each was validated against its ATS API or feed. Use `companies` to restrict the search, or `companyUrls` for any board that isn't indexed.

**Why do some jobs have no salary?**
Only some employers publish pay: as structured ranges (mostly Ashby, Lever, Recruitee and Personio) or as a stated range in the description, such as US pay-transparency ranges on Greenhouse. The first is `salary_source: "structured"`, the second `"description"` (read with fixed rules, only when the run reads the description). Pay is never estimated: a job that states none has `null` salary fields.

**How are seniority, years of experience and visa sponsorship determined?**
By fixed, published rules, not by an AI model, so the same posting always gives the same answer. `seniority` comes from title words ("Senior", "Staff Engineer", "Head of", "Werkstudent"…); "Product Manager" or "Account Manager" are not people-manager titles and stay `null` unless the title has another level word. `years_experience_min` takes the first required "N+ years" in the description and ignores company-age phrases ("founded 20 years ago"). `visa_sponsorship` is `false` whenever the posting rules sponsorship out, even if it also mentions it positively. Anything ambiguous stays `null`.

**Can I get only new jobs every day?**
Yes. Schedule the Actor with `sinceLastRun: true`. Each run returns and charges only jobs that no earlier run with the same filters delivered.

**Can I call it from Python, JavaScript, Make, Zapier or an AI agent?**
Yes. Run it through the Apify API or the official Python/JavaScript clients. You can connect it to Make, Zapier, n8n, Slack or Google Sheets through Apify integrations, or expose it to AI agents through the Apify MCP server.

### Related factpipe Actors

- [Career Page Scraper](https://apify.com/factpipe/company-jobs-scraper): give it a company *homepage* and it finds the careers page and ATS for you.

### Reliability

Official ATS APIs only. The Actor uses retries with backoff, per-host rate limits and structured failure reporting, and writes a `RUN_SUMMARY` record on every run. Its daily auto-test input has a built-in live fallback.

# Actor input Schema

## `keywords` (type: `array`):

Words or phrases to find (case-insensitive). A title matches at a word start ("engineer" matches "Engineering Manager"); description matching needs every word of the keyword, and covers the first ~1,500 characters. Results are ranked: title matches first. Leave empty for all jobs, newest first.

## `keywordMatch` (type: `string`):

"any": a job needs at least one keyword. "all": a job needs every keyword.

## `keywordScope` (type: `string`):

title: keywords must appear in the job title. title_and_description: in the title, or (every word of the keyword) in the department, team or the first ~1,500 characters of the description.

## `excludeKeywords` (type: `array`):

Drop jobs whose title contains any of these, e.g. "senior", "intern".

## `locations` (type: `array`):

City, state, country or region as written in the posting (e.g. "Berlin", "California", "Remote (EU)"), or a 2-letter ISO country code (e.g. "US", "DE"). A job matches if any location matches.

## `remote` (type: `string`):

remote_only: remote jobs only. onsite_only: excludes jobs marked remote (on-site, hybrid and unspecified remain).

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

Only jobs first published in the last N days. Empty = any age.

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

Only these companies: company names ("Datadog") or board tokens ("datadog", "greenhouse:datadog").

## `ats` (type: `array`):

Only jobs from these applicant tracking systems. Empty = all.

## `departments` (type: `array`):

Substring match on department or team, e.g. "engineering", "sales".

## `employmentTypes` (type: `array`):

Normalized employment type. Jobs whose ATS does not state one (most Greenhouse boards) are excluded when this is set.

## `seniority` (type: `array`):

Only jobs at these levels, read from the job title by fixed rules (no AI): intern (Intern, Working student, Co-op, Trainee, Apprentice), entry (Junior, Graduate, Associate, Engineer I), mid (Mid-level, Engineer II, Intermediate), senior (Senior, Staff engineer, Principal, Engineer III), lead (Lead, Team lead, Supervisor), manager (people managers; not Product/Project/Account Manager), director (Director, Head of, VP), executive (Chief ... Officer, CEO/CTO, SVP, President, Founder). Common German, French, Spanish, Dutch and Portuguese markers count too. Jobs whose title has no level marker ("Software Engineer") are excluded when this is set. Empty = all.

## `maxResults` (type: `integer`):

Maximum number of jobs to return (and charge for). With keywords the most relevant jobs come first (title matches before department and description matches); without keywords the newest.

## `maxPerCompany` (type: `integer`):

Cap on jobs returned from any single company, so one employer posting many near-identical roles can't fill your results. Empty = no cap.

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

Fetch the full plain-text description (HTML stripped, contact details redacted, max 20,000 characters) live from the company's ATS for every delivered job. Adds a few seconds per company. A 300-character snippet is always included.

## `sinceLastRun` (type: `boolean`):

Incremental feed: remembers delivered jobs per filter combination (in a named key-value store in your account) and returns only jobs posted since, so a scheduled run never re-delivers or re-charges a job.

## `companyUrls` (type: `array`):

Optional. Fetch these boards live instead of searching the index, e.g. https://job-boards.greenhouse.io/gitlab, https://jobs.lever.co/acme, https://jobs.ashbyhq.com/acme, https://apply.workable.com/acme, https://acme.recruitee.com or "greenhouse:gitlab". All filters above still apply.

## Actor input object example

```json
{
  "keywords": [
    "engineer"
  ],
  "keywordMatch": "any",
  "keywordScope": "title_and_description",
  "remote": "remote_only",
  "postedWithinDays": 7,
  "maxResults": 20,
  "maxPerCompany": 3,
  "includeDescription": true,
  "sinceLastRun": false
}
```

# Actor output Schema

## `resultsDatasetUrl` (type: `string`):

No description

## `runSummary` (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 = {
    "keywords": [
        "engineer"
    ],
    "remote": "remote_only",
    "postedWithinDays": 7,
    "maxResults": 20,
    "maxPerCompany": 3
};

// Run the Actor and wait for it to finish
const run = await client.actor("factpipe/ats-jobs-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 = {
    "keywords": ["engineer"],
    "remote": "remote_only",
    "postedWithinDays": 7,
    "maxResults": 20,
    "maxPerCompany": 3,
}

# Run the Actor and wait for it to finish
run = client.actor("factpipe/ats-jobs-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 '{
  "keywords": [
    "engineer"
  ],
  "remote": "remote_only",
  "postedWithinDays": 7,
  "maxResults": 20,
  "maxPerCompany": 3
}' |
apify call factpipe/ats-jobs-feed --silent --output-dataset

```

## MCP server setup

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