# Career Site Jobs API — 8 ATS, 10k+ company career sites (`jharney/career-site-jobs-api`) Actor

Search open roles directly from company career sites (8 ATS platforms), fresh at run time, or scan company domains for ATS, open roles and hiring signals. No login, no proxies, no LinkedIn.

- **URL**: https://apify.com/jharney/career-site-jobs-api.md
- **Developed by:** [Jack Harney](https://apify.com/jharney) (community)
- **Categories:** Jobs, Lead generation, AI
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

Pay per event

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?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.
Actors are written with capital "A".

## How to integrate an Actor?

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

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## Career Site Jobs API — jobs straight from company career pages (Greenhouse, Lever, Ashby, Workday, SmartRecruiters, Workable, Recruitee, Teamtailor)

Search **open roles directly on 10,000+ company career sites**, or hand it a list of **company domains** and get each company's ATS, open roles and a hiring summary. Every result is fetched live from the employer's own job board at run time — no stale database, no job-board aggregators, no LinkedIn, no login, no proxies.

**Why career sites?** Jobs on the employer's own ATS are real, current and deduplicated at the source. Aggregators lag hours to days and are full of reposts and recruiter listings. This Actor reads the same public job-board APIs the companies' careers pages use, so you get the posting the moment it is live.

### What you get

| Mode | Input | Output |
|---|---|---|
| **Search** | keywords, location, department, remote, posted-within-N-hours, ATS filter | one row per matching job, live from every indexed career site |
| **Companies** | company domains (e.g. `stripe.com`) and/or board URLs | one summary row per company (ATS detected, open roles, new roles in 7/30 days, departments, locations, hiring velocity) plus the matching jobs |

Each job row includes: `title`, `company`, `location`, `isRemote`, `department`, `team`, `employmentType`, `postedAt`, `updatedAt`, `url`, `applyUrl`, `ats`, `boardSlug`, `boardUrl`, plus ATS-specific extras (Lever/Ashby/Recruitee salary when published, SmartRecruiters experience level and industry, Workday time type). Turn on **Include full job descriptions** to add `descriptionText` and `descriptionHtml`.

### Coverage

- **8 ATS platforms**: Greenhouse, Lever, Ashby, Workday, SmartRecruiters, Workable, Recruitee, Teamtailor.
- **10,900+ career sites, ~1.27 million open roles** in the index (validated live; refreshed regularly — the run log shows the index date).
- Any career site on these platforms works in **companies mode** even if it is not in the index yet: give the domain or the board URL.

### Typical uses

- **Sales & lead generation** — companies hiring SDRs, AEs, RevOps or a specific role are buying tools for that team. Scan your target-account domains and rank by `newLast30Days` and `hiringVelocity`.
- **Recruiting & job boards** — fresh, deduplicated postings for a niche board or a candidate alert, with `postedSinceHours` for "new since yesterday".
- **Market & competitor intelligence** — track which teams competitors are growing, where they open offices, remote share by company.
- **AI agents / MCP** — plain JSON, stable field names, small runs are cheap: point an agent at a domain and get a hiring summary in seconds.

### Input examples

**New remote sales jobs posted in the last 7 days**

```json
{ "mode": "search", "department": "sales", "remoteOnly": true, "postedSinceHours": 168 }
```

**Account executive roles in New York on Greenhouse and Ashby boards**

```json
{ "mode": "search", "query": "account executive", "location": "New York", "ats": ["greenhouse", "ashby"] }
```

**Hiring summary for a list of target accounts**

```json
{ "mode": "companies", "companyDomains": ["stripe.com", "notion.so", "cloudflare.com"], "titleIncludes": ["sales", "account executive", "SDR"] }
```

**A single board, full descriptions**

```json
{ "mode": "companies", "boardUrls": ["https://boards.greenhouse.io/stripe"], "includeDescription": true }
```

### Pricing

Pay per event, no subscription:

| Event | Price | When |
|---|---|---|
| `actor-start` | $0.005 | once per run |
| `job-result` | $0.002 ($2 per 1,000 jobs) | per job pushed to the dataset |
| `company-scanned` | $0.005 | per company domain / board URL in companies mode |
| `job-description` | $0.001 | per job when *Include full job descriptions* is on |

Platform compute is included in these prices. Set **Maximum total charge** on the run to cap spend; the Actor stops cleanly at the cap and tells you in the log. Free-plan users can run it within their free monthly credit.

### How it works

1. **Search mode** scans the index of validated career sites in parallel (default 48 at a time), applies your filters to each board's live job list, and streams matches to the dataset. A full-index scan takes a few minutes; use `maxBoards` for a quick test or the `ats` filter to narrow it.
2. **Companies mode** loads the company homepage, follows its careers link(s), detects any of the 8 ATS platforms, verifies the board, pulls every open role and builds the summary. Board URLs skip discovery.
3. Only the vendors' public job-board endpoints are used — the same ones the companies embed on their own websites. No authentication, no scraping behind logins, no personal data.

### Limits and honesty notes

- Workday sites are only detected in companies mode when the company's careers page links to them directly (Workday has no slug convention to guess).
- Some boards omit posting dates (a few Workday and Teamtailor sites); those jobs are excluded when `postedSinceHours` is set and counted as `undatedRoles` in company summaries.
- `postedAt` on Workday is derived from the board's "Posted N days ago" text unless descriptions are fetched (then the exact date is used).
- Very large boards (retail chains with 10,000+ roles) are capped by `maxJobsPerBoard` (default 500).
- Title keyword matching is literal and case-insensitive; use `titleIncludes` for synonyms.

### Output example (job)

```json
{
  "title": "Account Executive, Mid-Market",
  "company": "Notion",
  "location": "New York, NY",
  "isRemote": false,
  "department": "Sales",
  "employmentType": "FullTime",
  "postedAt": "2026-09-08T17:02:11.000Z",
  "url": "https://jobs.ashbyhq.com/notion/…",
  "ats": "ashby",
  "boardSlug": "notion"
}
```

### Output example (company summary)

```json
{
  "recordType": "company",
  "domain": "cloudflare.com",
  "atsDetected": ["greenhouse"],
  "openRoles": 353,
  "newLast7Days": 41,
  "newLast30Days": 132,
  "remoteRoles": 60,
  "hiringVelocity": "moderate",
  "departments": [{ "name": "Engineering", "count": 140 }, { "name": "Sales", "count": 62 }]
}
```

### Integrations

Runs on schedule, via API, or from the Apify MCP server; export to JSON, CSV, Excel, or push to Google Sheets, Airtable, Slack, Make, Zapier, n8n and webhooks through Apify integrations.

### Feedback

Missing an ATS or a field? Open an issue on the Actor's Issues tab — new platforms are added by request when they expose a public job-board API.

# Actor input Schema

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

<b>search</b>: find jobs across all indexed company career sites. <b>companies</b>: give company domains (or board URLs) and get each company's ATS, open roles and a hiring summary.

## `query` (type: `string`):

All words must appear in the job title (case-insensitive). Example: <code>account executive</code>. Leave empty and use the other filters for broad pulls.

## `titleIncludes` (type: `array`):

Job title must contain at least one of these phrases. Example: \["SDR", "sales development", "BDR"].

## `titleExcludes` (type: `array`):

Drop jobs whose title contains any of these phrases. Example: \["intern", "senior"].

## `location` (type: `string`):

Substring match on the job's location(s). Examples: <code>New York</code>, <code>United States</code>, <code>London</code>, <code>remote</code>.

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

Keep only jobs the ATS marks as remote (or whose location says remote).

## `department` (type: `string`):

Substring match on the ATS department or team field. Examples: <code>Sales</code>, <code>Engineering</code>, <code>Marketing</code>.

## `postedSinceHours` (type: `integer`):

0 = no time filter. 24 = last day, 168 = last week, 720 = last 30 days. Jobs without a posting date are excluded when this is set.

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

Restrict the scan to specific applicant tracking systems. Empty = all.

## `companyDomains` (type: `array`):

Company websites to scan, e.g. <code>stripe.com</code>. The Actor finds the careers page, detects the ATS and pulls every open role. One <b>company-scanned</b> event per domain.

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

Direct career-site / job-board URLs (Greenhouse, Lever, Ashby, Workday, SmartRecruiters, Workable, Recruitee, Teamtailor). Skips discovery.

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

Adds <code>descriptionText</code> and <code>descriptionHtml</code>. Costs one extra <b>job-description</b> event per job and is slower for Workday / Workable / SmartRecruiters (one request per job).

## `maxJobs` (type: `integer`):

Stop after this many matching jobs (0 = unlimited, bounded by Maximum total charge).

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

Cap per company board (protects against huge Workday tenants).

## `maxBoards` (type: `integer`):

0 = scan the whole index. Set e.g. 500 for a quick test run.

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

Upper bound on parallel career-site requests (split per ATS; Workday and Workable are capped low because they rate-limit).

## Actor input object example

```json
{
  "mode": "search",
  "query": "account executive",
  "remoteOnly": false,
  "postedSinceHours": 0,
  "includeDescription": false,
  "maxJobs": 300,
  "maxJobsPerBoard": 500,
  "maxBoards": 0,
  "concurrency": 100
}
```

# Actor output Schema

## `results` (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 = {
    "mode": "search",
    "query": "account executive",
    "maxJobs": 300
};

// Run the Actor and wait for it to finish
const run = await client.actor("jharney/career-site-jobs-api").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 = {
    "mode": "search",
    "query": "account executive",
    "maxJobs": 300,
}

# Run the Actor and wait for it to finish
run = client.actor("jharney/career-site-jobs-api").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 '{
  "mode": "search",
  "query": "account executive",
  "maxJobs": 300
}' |
apify call jharney/career-site-jobs-api --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,jharney/career-site-jobs-api"
        }
    }
}
```

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/bRqwrElVE8DpZKdVC/builds/d9pfo4KKd2eZB9efB/openapi.json
