# Career-Site Jobs — Paste a Domain (`steadyfetch/company-jobs-by-domain`) Actor

Never pay for a domain we couldn't resolve. Paste a company domain — we find its Greenhouse, Lever, Ashby or Workday board and return every live opening. Nine ATS platforms, one box — no board tokens needed.

- **URL**: https://apify.com/steadyfetch/company-jobs-by-domain.md
- **Developed by:** [Steadyfetch Team](https://apify.com/steadyfetch) (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

from $0.80 / 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.
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?

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 — Paste a Domain

**Never pay for a domain we couldn't resolve.** Paste a company domain — we find its
Greenhouse, Lever, Ashby or Workday board and return every live opening. Nine ATS
platforms, one box — no board tokens needed.

**From $0.80/1,000 jobs** — all-inclusive pay per event, no start fee, charged only on
delivery. Issues answered in about 3 hours.

Every row carries `charged` and `missReason`, so you can reconcile the invoice from the
dataset itself without opening the console. **Only rows with `charged: true` were billed.**

***

### Output — a real row

```json
{
  "source": "greenhouse",
  "sourceJobId": "6136160004",
  "jobUrl": "https://job-boards.greenhouse.io/vercel/jobs/6136160004",
  "applyUrl": "https://job-boards.greenhouse.io/vercel/jobs/6136160004",
  "title": "Account Executive, Commercial",
  "company": "Vercel",
  "companyDomain": "vercel.com",
  "location": { "raw": "Hybrid - London", "city": "Hybrid - London", "region": null, "country": null },
  "isRemote": null,
  "employmentType": null,
  "department": "Account Executive",
  "salary": null,
  "postedAt": "2026-08-06T16:50:10.000Z",
  "updatedAt": "2026-08-18T22:06:19.000Z",
  "scrapedAt": "2026-08-27T10:00:00.000Z",
  "descriptionText": "About Vercel:\n\n Vercel is the agentic infrastructure company. We free people and agents to ship what's next…",
  "descriptionHtml": "<div class=\"content-intro\"><h2>About Vercel:</h2>…",
  "atsPlatform": "greenhouse",
  "atsBoardToken": "vercel",
  "resolvedVia": "careers-link",
  "dedupeKey": "greenhouse:vercel:6136160004",
  "charged": true,
  "missReason": null
}
```

Plus **one company row per domain** — `domain`, `companyName`, `atsPlatform`, `boardUrl`,
`openRoleCount`, `sharedRoleCount` (openings already delivered — and charged once — under
another company in the same run), `totalOpenRoles`, `resolved`, `resolvedVia` — and **one summary row**
with `delivered`, `stoppedBy`, `resumeCursor` and `chargedEvents`.

**See a whole run's output before you spend anything:**
[real dataset from a verified run](https://api.apify.com/v2/datasets/npRpZ4NgjIFneLsQW/items?clean=true\&format=json)
— six live openings from `vercel.com` and `linear.app`, their two company rows, and the run
summary, exactly as this actor returned them.

| field | notes |
|---|---|
| `title` · `company` · `companyDomain` | `company` is filled when the board publishes it |
| `location{raw,city,region,country}` · `isRemote` | as the board states it — never inferred |
| `employmentType` · `department` | |
| `salary{min,max,currency,period,isEstimate}` | `null` unless the company published a range |
| `postedAt` · `updatedAt` · `scrapedAt` | ISO 8601; `null` when the board only gives relative text |
| `descriptionText` · `descriptionHtml` | full description where the board's API includes it |
| `jobUrl` · `applyUrl` | the company's own posting, not a re-hosted copy |
| `atsPlatform` · `atsBoardToken` · `resolvedVia` | how we found the board |
| `charged` · `missReason` · `dedupeKey` | the reconciliation trio |

### Agent / API paste-block

```
Actor:      steadyfetch/company-jobs-by-domain
Required:   domains        (array of company domains, careers URLs, board URLs or names)
Optional:   atsFilter      (array: greenhouse | lever | ashby | workday | workable |
                            smartrecruiters | rippling | personio | teamtailor)
            remoteOnly           (boolean, default false — keep only openings the board
                                  marks remote; filtered openings are never charged)
            postedWithinDays     (integer 1-30 — keep only openings posted that recently;
                                  filtered openings are never charged)
            maxItems             (integer, default 1000 — hard cap for the whole run)
            maxItemsPerCompany   (integer, default 200)
            maxRunSeconds        (integer, default 900 — clean stop, never a timeout kill)
Charges:    job              once per delivered opening
            company-checked  once per company with a definitive answer (including a
                             verified zero-openings result)
Build spec: https://apify.com/steadyfetch/company-jobs-by-domain/api
Token:      https://console.apify.com/settings/integrations
```

```bash
curl -X POST "https://api.apify.com/v2/acts/steadyfetch~company-jobs-by-domain/run-sync-get-dataset-items?token=$APIFY_TOKEN" \
  -H 'Content-Type: application/json' \
  -d '{"domains":["stripe.com","linear.app"],"maxItemsPerCompany":50}'
```

***

### Hiring platforms

Greenhouse · Lever · Ashby · Workday · Workable · SmartRecruiters · Rippling · Personio ·
Teamtailor. Each is read from that platform's own public job-board API, so the data is
whatever the company published, unchanged.

**How a domain becomes a board** (`resolvedVia` tells you which one happened):

| `resolvedVia` | what it means |
|---|---|
| `board-url` | you pasted the board URL — no lookup needed |
| `careers-link` | the company's own careers page links its board |
| `token-pattern` | the domain name matched a board token **and that board returned live openings** |
| `name-probe` | same, from a company name instead of a domain |

A board found by guessing the token only counts when real openings come back. An empty
board reached by guesswork is not a match, so it is never charged.

### What you are never charged for

| situation | `missReason` | run status |
|---|---|---|
| No hiring board found for the domain | `UNRESOLVED_DOMAIN` | SUCCEEDED — the row lists every platform checked |
| The board rate-limited or dropped us | `THROTTLED` | SUCCEEDED — re-runnable, and the row says so |
| The board answered with an access challenge | `CHALLENGED` | SUCCEEDED — re-runnable |
| The board was unavailable this run | `SOURCE_UNAVAILABLE` | SUCCEEDED — re-runnable |
| The board answered and listed nothing | `CLEAN_EMPTY` | SUCCEEDED |
| A domain, URL or name we could not read | `USER_INPUT` | SUCCEEDED — the row names the fix |
| Your own `maxItems` / `maxRunSeconds` / cost cap | `STOPPED_AT_LIMIT` | SUCCEEDED — summary row + `resumeCursor` |

The one exception: **`COMPANY_NO_OPENINGS`** charges the `company-checked` event and no
job rows. Confirming a company is *not* hiring is a real answer, and it is the answer
that costs you the least.

We never guess. A rate limit is reported as a rate limit, not as "this company has no
board" — a temporary problem is never dressed up as a permanent verdict.

**This actor may fail when a hiring platform changes things.** The two you are most likely
to see are `UNRESOLVED_DOMAIN` (we checked every platform and found no board) and
`THROTTLED` (a board rate-limited us). Both ship as a row with **`charged: false`**, the
run still SUCCEEDS, and the row says whether re-running can help.

### Filters you can set, and what they cost you

`remoteOnly` and `postedWithinDays` narrow what is **delivered**, and an opening they
leave out is never charged. They lean on what each board actually publishes: Greenhouse
and Workday publish no remote flag at all, and a few boards publish no posting date. An
opening we cannot check against your filter is left out too — and the company's own row
says how many, so a filter can never read as "this company has no openings". A board
emptied by your filters keeps `missReason: null` for exactly that reason.

### Limits are hard limits

`maxItems`, `maxItemsPerCompany` and `maxRunSeconds` stop the run exactly where you set
them. The run still finishes **successfully**, the summary row names which limit bound,
and `resumeCursor` lists the companies that were not reached — so you continue from there
instead of paying to re-walk what you already have.

**And they hold across a restart.** If the platform moves your run to another server
mid-way — or you resurrect it yourself — the run reads back what it already delivered and
picks up from there: no duplicate rows, no second charge for an opening you already have,
and your row cap still means what it says. Resurrecting a run that already finished costs
nothing and returns the same dataset.

### FAQ

**The company isn't on any ATS — what now?**
The company row lists every platform that was checked. If you know the board URL, paste it
directly (`https://jobs.lever.co/acme`) and we skip the lookup entirely.

**Can I search jobs across boards instead of by company?**
Not with this actor — it answers "is *this company* hiring, and for what". A job board URL
(LinkedIn, Indeed, Glassdoor) is rejected with a guidance row rather than treated as an
employer.

**How do I chain this after a company-list scraper?**
Feed the `domains` array from any actor that outputs company domains. Same-company
duplicates across input shapes are delivered once and charged once — the later
company's row reports them in `sharedRoleCount` instead of claiming them again.

**Why is `company` sometimes empty?**
Several board APIs do not publish the employer name in their listing payload. We leave the
field `null` rather than invent one; `companyDomain` and the company row always identify it.

**Does `{}` cost anything?**
No. With no domains it returns uncharged sample rows so you can see the exact output shape
before spending anything.

***

### Steadyfetch jobs suite

One actor per source, one job each, the same row shape — so a pipeline built on one source takes the
next without a rewrite. All-inclusive pay per event, no start fee, charged only on delivery.

| Source | Actor |
|---|---|
| Indeed | **[Indeed Jobs — Stops at Your Limit](https://apify.com/steadyfetch/indeed-jobs-scraper)** |
| A company's own career site (paste a domain) | **this actor** |
| Glassdoor, with the employer rating | **[Glassdoor Jobs + Employer Rating](https://apify.com/steadyfetch/glassdoor-jobs-scraper)** |
| Several boards at once, de-duplicated | **[Multi-Board Jobs — No Duplicates](https://apify.com/steadyfetch/multi-job-board-scraper)** |

**The rest of the steadyfetch shelf** — same contract everywhere: all-inclusive pay per event,
no start fee, charged only on delivery.

| Family | Actors |
|---|---|
| Ad creative intelligence | [Facebook](https://apify.com/steadyfetch/facebook-ads-transcript-scraper) · [Google Ads video](https://apify.com/steadyfetch/google-ads-video-transcript-scraper) · [TikTok](https://apify.com/steadyfetch/tiktok-ads-transcript-scraper) · [LinkedIn](https://apify.com/steadyfetch/linkedin-ads-transcript-scraper) · [Google Ads text & OCR](https://apify.com/steadyfetch/google-ads-creative-text-scraper) |
| Trends & keywords | [Google Trends](https://apify.com/steadyfetch/google-trends-scraper) · [Trends Now](https://apify.com/steadyfetch/google-trends-now-scraper) · [Breakout keywords](https://apify.com/steadyfetch/breakout-keywords-scraper) · Autocomplete keywords · Keyword volume & CPC · [Social trends](https://apify.com/steadyfetch/social-trends-scraper) |
| YouTube transcripts | [YouTube videos](https://apify.com/steadyfetch/youtube-transcript-scraper) · [YouTube channels](https://apify.com/steadyfetch/youtube-channel-transcripts) |
| Instagram | [Reel transcripts](https://apify.com/steadyfetch/instagram-reel-transcript-scraper) · [Profile posts](https://apify.com/steadyfetch/instagram-profile-posts) |
| **Jobs** | [Indeed](https://apify.com/steadyfetch/indeed-jobs-scraper) · [Career sites by domain](https://apify.com/steadyfetch/company-jobs-by-domain) · [Glassdoor](https://apify.com/steadyfetch/glassdoor-jobs-scraper) · [Multi-board](https://apify.com/steadyfetch/multi-job-board-scraper) |
| Amazon | [Products](https://apify.com/steadyfetch/amazon-product-scraper) · [Search](https://apify.com/steadyfetch/amazon-search-scraper) · Bestsellers · Sellers |
| Any media file | [Speech to Text](https://apify.com/steadyfetch/media-transcriber) · any link or file |

Unlinked names are publishing shortly on the same account — search **steadyfetch** on Apify Store.

# Actor input Schema

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

Company domains (stripe.com), careers-page URLs (https://stripe.com/jobs), board URLs (https://jobs.lever.co/leverdemo) or plain company names. Leave the default in place to see uncharged sample rows first.

## `atsFilter` (type: `array`):

Restrict the search to named platforms. Leave empty to check all of them.

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

Only openings the board says were posted in the last N days. Openings a board publishes no posting date for are left out too, and the company's own row says how many. Openings left out are never charged.

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

Keep only openings the board marks remote. Greenhouse and Workday publish no remote flag, so their openings are left out and the company's own row says so. Openings left out are never charged.

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

Hard cap on delivered jobs across every company in this run.

## `maxItemsPerCompany` (type: `integer`):

Hard cap on delivered jobs from any single company.

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

The run stops cleanly before this many seconds and reports what is left, instead of being killed by a timeout.

## Actor input object example

```json
{
  "domains": [
    "stripe.com",
    "linear.app"
  ],
  "remoteOnly": false,
  "maxItems": 1000,
  "maxItemsPerCompany": 200,
  "maxRunSeconds": 900
}
```

# Actor output Schema

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

One row per live opening: title, company, location, salary, posted date, description, apply link, and which hiring platform it came from. Every row carries `charged` and `missReason`, so the invoice reconciles from the dataset itself. Only rows with charged = true were billed.

## `companies` (type: `string`):

One row per company you asked about: which hiring board it resolved to, how it was found, and how many live openings it had — including a definitive zero. Companies we could not positively identify are never charged.

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

Delivered count, companies resolved, uncharged misses, what stopped the run, and the charged-event totals.

## `errors` (type: `string`):

Present only when a hiring board rate-limited, blocked or dropped the request after retries: the company and the reason. These are re-runnable, not permanent.

# 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": [
        "stripe.com",
        "linear.app"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("steadyfetch/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 = { "domains": [
        "stripe.com",
        "linear.app",
    ] }

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

```

## MCP server setup

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