# Company Career Pages Jobs API (Greenhouse, Lever, Ashby+) (`interconnected_seaport/ats-jobs-feed`) Actor

Open jobs from company career pages via official public job-board endpoints: Greenhouse, Lever, Ashby, SmartRecruiters, Recruitee, Teamtailor and Personio. Filters, salary when published, new-only mode. No login or proxies.

- **URL**: https://apify.com/interconnected_seaport/ats-jobs-feed.md
- **Developed by:** [Zenith Ops](https://apify.com/interconnected_seaport) (community)
- **Categories:** Jobs, Lead generation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $3.00 / 1,000 job listings

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

## Company Career Pages Jobs API (Greenhouse, Lever, Ashby+)

Get the open jobs of the companies you choose as clean, structured rows. The actor reads the **official public job-board endpoints** that employers expose for embedding and indexing on **Greenhouse, Lever, Ashby, SmartRecruiters, Recruitee, Teamtailor and Personio**. No login, no HTML scraping, no proxies.

You provide the companies (a slug like `figma`, `greenhouse:figma`, or a career-page URL such as `https://jobs.lever.co/spotify`). With just a slug, the actor probes the seven platforms and uses the one that has jobs.

### Use cases

- Recruiting and talent teams tracking competitor hiring.
- Sales and BD teams using open roles as a buying signal for a target account list.
- Job boards and newsletters that aggregate roles from a curated set of employers.
- Market research: which companies hire for which roles, where, and at what published salary.

### Input

| Field | Description |
|---|---|
| `companies` (required, max 500) | Slugs, `ats:slug` or career URLs |
| `keywords` / `excludeKeywords` | Any-match on title (and description when loaded) |
| `locationContains` | Any-match, case-insensitive, on locations |
| `countries` | ISO-2 codes; only jobs with an explicit country can match |
| `remoteOnly` | Only jobs explicitly flagged remote |
| `departments`, `employmentTypes` | "Contains" match |
| `postedWithinDays` | 0 = any; jobs without a date are dropped when set |
| `includeDescription` | Plain-text description (default off; slower) |
| `maxJobsPerCompany` | Default 200, max 5000; applied after filters (with `includeDescription` on: before filters) |
| `maxItems` | Default 200, max 20000; caps charged results |
| `onlyNewSinceLastRun` | Return only jobs not delivered before for the same companies and filters |
| `concurrency` | Default 5, max 10 |
| `includeCompanySummary` | Default true: writes the `SUMMARY` key-value record |

Different filters combine with AND; entries inside one list combine with OR.

### Output

Each dataset row is one job: `ats, companySlug, companyName, jobId, title, department, team, locations, location, country, remote, workplaceType, employmentType, seniority, postedAt, updatedAt, jobUrl, applyUrl, salary {min,max,currency,period,text}, descriptionText, sourceUrl, scrapedAt`. Unknown values are `null`. Salary is only filled when the employer publishes it; country and remote flags come only from explicit fields, never guessed from titles or city names.

The key-value record `SUMMARY` lists `requested`, `resolved`, `notFound`, `errors`, `jobsPushed` and per-company counts. Companies that are not found or fail upstream are never charged.

### Pricing

| Event | Price |
|---|---|
| Actor start | $0.00005 (default Apify event) |
| Job returned | $0.003 ($3 per 1,000 jobs) |

You pay per job written to the dataset. The "max total charge" setting of your run is respected: the actor stops when the limit is reached. Use `maxItems` to cap spend.

### Examples

Input:

```json
{
  "companies": ["greenhouse:figma", "https://jobs.lever.co/spotify", "ramp"],
  "keywords": ["engineer"],
  "excludeKeywords": ["intern"],
  "remoteOnly": true,
  "postedWithinDays": 30,
  "maxItems": 100
}
```

curl:

```bash
curl -X POST "https://api.apify.com/v2/acts/interconnected_seaport~ats-jobs-feed/run-sync-get-dataset-items?token=YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"companies":["greenhouse:figma"],"keywords":["engineer"],"maxItems":50}'
```

Python:

```python
from apify_client import ApifyClient

client = ApifyClient("YOUR_TOKEN")
run = client.actor("interconnected_seaport/ats-jobs-feed").call(run_input={
    "companies": ["greenhouse:figma"], "keywords": ["engineer"], "maxItems": 50,
})
for job in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(job["companyName"], job["title"], job["location"])
```

### Scheduled new-job alerts

Turn on `onlyNewSinceLastRun` and schedule the actor. State is stored in a named key-value store in your account, derived from your companies and filters, so changing them starts a fresh history. Jobs are marked as seen only when delivered, so jobs cut off by `maxItems` appear in the next run. Up to 200,000 job keys are kept (oldest dropped first).

### FAQ

**Do I need to know the job platform?** No. A plain slug is auto-detected. If the same slug exists on several platforms, the one with the most jobs is used and the others are listed in the `SUMMARY`.

**Why is a company "not found"?** It has no public board on the supported platforms under that slug. Try the exact slug from its careers URL.

**Why is `country` empty?** Only some platforms publish an explicit country code. We do not guess.

**Are descriptions available everywhere?** Yes with `includeDescription`, but SmartRecruiters needs one extra request per job.

### Legal and ethics

Only official public endpoints that employers expose for embedding and indexing are read: no login, no proxies, no anti-bot bypass. The actor respects 404 and 429 responses (with limited retries). Job data belongs to the employers. Job posts are generally not personal data; the actor does not extract recruiter or contact names. You are responsible for lawful use of the data.

### Limitations

- Only seven platforms. Workday, Workable, LinkedIn and others are not supported.
- You must supply the companies; this is not a database of all jobs.
- Fields vary by platform and are `null` when not published.

# Actor input Schema

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

Company slugs ("figma" auto-detects the job platform), "ats:slug" (e.g. "greenhouse:figma", "lever:spotify") or career-page URLs (e.g. https://jobs.lever.co/spotify). Max 500.

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

Keep jobs whose title contains any of these words (also the description when "Include description" is on).

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

Drop jobs whose title (or loaded description) contains any of these words, e.g. intern.

## `locationContains` (type: `array`):

Keep jobs where any location contains one of these texts (case-insensitive), e.g. Stockholm, Remote.

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

ISO 3166-1 alpha-2 codes, e.g. SE, DE. Only jobs with an explicitly published country can match; many platforms do not publish one.

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

Keep only jobs the employer explicitly flags as remote.

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

Keep jobs whose department or team contains any of these texts, e.g. Engineering.

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

e.g. full-time, contract, intern. Jobs without a published type are dropped when this is set.

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

0 = any age. Jobs without a posting or update date are dropped when this is set.

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

Add the plain-text job description (max 20,000 characters). Slower, especially for SmartRecruiters (one extra request per job).

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

Maximum jobs delivered per company (applied after filters). With 'Include description' on, the cap applies to jobs read before filtering.

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

Maximum number of jobs returned (and charged) in this run.

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

Return only jobs not delivered by an earlier run with the same companies and filters. State is kept in a named key-value store in your account (up to 200,000 job keys).

## `concurrency` (type: `integer`):

Companies fetched in parallel.

## `includeCompanySummary` (type: `boolean`):

Store a SUMMARY record in the key-value store listing companies not found, upstream errors and per-company counts. Never added to the dataset.

## Actor input object example

```json
{
  "companies": [
    "greenhouse:figma",
    "https://jobs.lever.co/spotify"
  ],
  "keywords": [
    "engineer"
  ],
  "excludeKeywords": [],
  "locationContains": [],
  "countries": [],
  "remoteOnly": false,
  "departments": [],
  "employmentTypes": [],
  "postedWithinDays": 0,
  "includeDescription": false,
  "maxJobsPerCompany": 200,
  "maxItems": 200,
  "onlyNewSinceLastRun": false,
  "concurrency": 5,
  "includeCompanySummary": true
}
```

# Actor output Schema

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

One row per open job.

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

Companies not found, errors and per-company counts.

# API

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

## JavaScript example

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

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

// Prepare Actor input
const input = {
    "companies": [
        "greenhouse:figma",
        "lever:spotify",
        "ashby:ramp"
    ],
    "keywords": [
        "engineer"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("interconnected_seaport/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 = {
    "companies": [
        "greenhouse:figma",
        "lever:spotify",
        "ashby:ramp",
    ],
    "keywords": ["engineer"],
}

# Run the Actor and wait for it to finish
run = client.actor("interconnected_seaport/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 '{
  "companies": [
    "greenhouse:figma",
    "lever:spotify",
    "ashby:ramp"
  ],
  "keywords": [
    "engineer"
  ]
}' |
apify call interconnected_seaport/ats-jobs-feed --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,interconnected_seaport/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/xzq1tTSDxcQTN1m1T/builds/kr1KvXwLWcYcncib0/openapi.json
