# Career Site Jobs API: Greenhouse, Lever, Ashby + 4 More ATS (`pewterdesk/company-jobs-by-domain`) Actor

Get every open job from a company's career site by domain. Auto-detects the ATS (Greenhouse, Lever, Ashby, Workable, SmartRecruiters, Recruitee, Personio) and returns normalized jobs with salary, location and remote type, or a hiring-signal row per company.

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

## Pricing

Pay per usage

This Actor is paid per platform usage. The Actor is free to use, and you only pay for the Apify platform usage, which gets cheaper the higher subscription plan you have.

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

## 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

## Career Site Jobs API: Greenhouse, Lever, Ashby + 4 More ATS

**Career site jobs API** for Greenhouse, Lever, Ashby, Workable, SmartRecruiters, Recruitee and Personio job boards, with the ATS detected automatically from the company's domain.&#x20;

**Give it company domains and get back every open job.** You don't need to know which applicant tracking system (ATS) a company uses. The tool scans the company's own careers pages to find its job board, then pulls the jobs from the ATS's official public job-board API. It returns:

- **One row per job**: title, department, team, location(s), country, remote/hybrid/on-site, employment type, posted date, salary (when published), job and apply URLs, and the full description as clean text.
- **Or one row per company** (*hiring signals*): open jobs, jobs posted in the last 30 days, newest posting, top departments and locations, remote share, a hiring intensity rating (high/medium/low/none) and sample titles.

**Supported ATSs:** Greenhouse · Lever (US & EU) · Ashby · Workable · SmartRecruiters · Recruitee · Personio

**Companies without a supported public board are free, and so are invalid lines.**

### Why this tool

- **Works from a plain list of domains.** Most job tools need the ATS and its board slug for every company. This one finds them for you, and you can still paste board URLs directly (`https://jobs.lever.co/spotify`).
- **One schema across 7 ATSs.** Combine Greenhouse and Lever companies in one spreadsheet without cleanup.
- **Filters before billing.** Filter by title keywords, excluded words, location, department, remote-only and posted within N days. You pay only for jobs that match.
- **Transparent matching.** Every row says how the board was found (`careers-page`, `board-name-match`, `board-slug-match` or `input-board-url`) and gives a confidence level.

### Who uses it

- **B2B sales and RevOps.** Hiring is buying intent. A company hiring 5 data engineers may need your data tool. Run your target-account list in *companies* mode each week.
- **Recruiters and staffing agencies.** Track every open role at your target clients in one sheet.
- **Job boards and newsletters.** Build niche feeds, such as remote ML jobs at Series B+ startups, from company lists.
- **Investors and analysts.** Use hiring velocity and department mix as a growth signal across a portfolio or market map.
- **AI agents.** One call answers "is X hiring for Y?"

### Input example

```json
{
  "companies": ["stripe.com", "linear.app", "huggingface.co", "https://jobs.lever.co/spotify"],
  "outputMode": "jobs",
  "titleKeywords": ["engineer", "data"],
  "excludeTitleKeywords": ["intern"],
  "locationKeywords": ["remote", "London"],
  "postedWithinDays": 30,
  "includeDescription": true
}
```

### Output examples

**Jobs mode** (shortened):

```json
{
  "companyName": "Spotify", "domain": null, "ats": "Lever", "boardUrl": "https://jobs.lever.co/spotify",
  "detection": "input-board-url", "confidence": "high",
  "jobId": "785989a6-…", "title": "AV Engineer - Platform", "department": "Engineering", "team": "IT and Network Engineering",
  "location": "Stockholm", "locations": ["Stockholm"], "country": "SE", "workplaceType": "on-site",
  "employmentType": "Permanent", "postedAt": "2026-10-09T09:18:28+00:00",
  "url": "https://jobs.lever.co/spotify/785989a6-…", "applyUrl": "https://jobs.lever.co/spotify/785989a6-…/apply",
  "salaryMin": null, "salaryMax": null, "salaryCurrency": null, "salaryText": null,
  "descriptionText": "What You'll Do\n• Own the AV experience across EMEA…"
}
```

**Companies mode** (shortened):

```json
{
  "domain": "figma.com", "companyName": "Figma", "found": true, "ats": "Greenhouse",
  "boardUrl": "https://job-boards.greenhouse.io/figma", "detection": "careers-page", "confidence": "high",
  "openJobs": 150, "matchingJobs": 150, "postedLast30Days": 35, "hiringIntensity": "high", "remoteShare": …,
  "topDepartments": [{"name": "…", "jobs": …}], "sampleTitles": ["…"]
}
```

The dataset has two ready-made table views, **Jobs** and **Company hiring signals**, for one-click CSV or Excel export. A `RUN_SUMMARY` record in the key-value store lists unresolved companies and companies with no matching jobs.

### Pricing (pay per event)

| Event | Price | When |
|---|---|---|
| Company resolved | **$0.003** | A company's job board was found **and** returned data (jobs mode: at least one matching job) |
| Job | **$0.0015** | Each job row returned (jobs mode only) |

Example: 100 company domains in companies mode cost at most $0.30. Fifty companies with 20 matching jobs each in jobs mode cost $0.15 + $1.50 = $1.65.

Set a **maximum cost per run**. The tool stops cleanly at your limit and never goes over it.

### How detection works

1. **Careers pages.** It reads `robots.txt`, then the homepage, links that look like careers or jobs pages, and the usual `/careers` and `/jobs` paths. It looks for links or embeds pointing to a supported job board. This is the highest-confidence method.
2. **Board-name match** (optional, on by default). It checks the company's name on supported ATS boards. A match is accepted only if the board's own company name matches the domain, or, for ATSs that don't expose a name, if the job descriptions mention the company. Turn this off with **ATS detection → Careers pages only** for maximum precision.

If a company uses an ATS we don't support yet (Workday, iCIMS, SuccessFactors, Taleo and others) or a custom careers site, it's reported as not found and you aren't charged. Paste a board URL if you know it.

### Data sources and compliance

- Jobs come only from the **official public job-board/posting APIs** that the ATS vendors provide so companies can publish their openings.
- No login and no scraping of LinkedIn or Indeed.
- Company websites are read lightly (a handful of pages per company) and **robots.txt is respected** by default.
- **No personal data is collected.** Recruiter names and emails present in some feeds are deliberately dropped.

### Limitations

- SmartRecruiters listings don't include descriptions in this version.
- Salary appears only when the employer publishes it through the ATS.
- Very large boards (thousands of jobs) can be capped with **Max jobs per company**.

Questions or a missing ATS? Open an issue in the **Issues** tab.

***

Built by **PewterDesk** ([pewterdesk.pages.dev](https://pewterdesk.pages.dev)). More tools: [apify.com/pewterdesk](https://apify.com/pewterdesk).

# Actor input Schema

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

One per line. Company domains (stripe.com), website URLs, work emails, or direct job-board URLs (https://jobs.lever.co/spotify, https://job-boards.greenhouse.io/airbnb, https://jobs.ashbyhq.com/linear). Domains are auto-detected; board URLs are used as-is.

## `outputMode` (type: `string`):

jobs = one row per open job (charged per job + per company). companies = one hiring-signal summary row per company (charged per company only: open jobs, jobs posted last 30 days, top departments/locations, remote share, hiring intensity).

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

Plain-text job description (jobs mode). Turn off for smaller, faster output. Not available for SmartRecruiters listings.

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

Whole-word, case-insensitive. E.g. engineer, data, sales, account executive. Leave empty for all jobs.

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

E.g. intern, senior, manager.

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

Matched against location, all locations, country and workplace type. E.g. London, Germany, US, remote.

## `departmentKeywords` (type: `array`):

E.g. engineering, sales, marketing.

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

Keep only jobs whose workplace type is remote.

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

Only jobs first published within this many days (jobs without a date are excluded when set).

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

Cap per company (before filters). Leave empty for all.

## `detectionMode` (type: `string`):

pages+guess = scan the company's homepage/careers pages for job-board links, then try matching board names on supported ATSs (verified against the company name/domain). pages = careers-page links only (highest precision).

## `respectRobotsTxt` (type: `boolean`):

Skip company web pages that robots.txt disallows (job-board APIs are unaffected).

## `maxConcurrency` (type: `integer`):

Companies processed in parallel.

## Actor input object example

```json
{
  "companies": [
    "stripe.com",
    "linear.app",
    "https://jobs.lever.co/spotify"
  ],
  "outputMode": "jobs",
  "includeDescription": true,
  "remoteOnly": false,
  "maxJobsPerCompany": 20,
  "detectionMode": "pages+guess",
  "respectRobotsTxt": true,
  "maxConcurrency": 5
}
```

# Actor output Schema

## `results` (type: `string`):

Normalized job postings and per-company hiring summaries (default dataset).

## `runSummary` (type: `string`):

Counts for this run (processed, failed, stopped at spending limit) as JSON.

# 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": [
        "stripe.com",
        "linear.app",
        "https://jobs.lever.co/spotify"
    ],
    "maxJobsPerCompany": 20
};

// Run the Actor and wait for it to finish
const run = await client.actor("pewterdesk/company-jobs-by-domain").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": [
        "stripe.com",
        "linear.app",
        "https://jobs.lever.co/spotify",
    ],
    "maxJobsPerCompany": 20,
}

# Run the Actor and wait for it to finish
run = client.actor("pewterdesk/company-jobs-by-domain").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": [
    "stripe.com",
    "linear.app",
    "https://jobs.lever.co/spotify"
  ],
  "maxJobsPerCompany": 20
}' |
apify call pewterdesk/company-jobs-by-domain --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,pewterdesk/company-jobs-by-domain"
        }
    }
}
```

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/39bQE6AVrOhgiSTx9/builds/BTJSSp4K9IH3zME1R/openapi.json
