# Career Site Jobs API – ATS job feeds with salaries (`omararida/career-site-jobs-api`) Actor

Job postings straight from company career sites via their ATS (Greenhouse, Lever, Ashby, Workable, SmartRecruiters, Workday, Oracle Recruiting). Normalized fields, salary ranges extracted, keyword/location filters, and a monitoring mode that returns only new jobs.

- **URL**: https://apify.com/omararida/career-site-jobs-api.md
- **Developed by:** [Omar Arida](https://apify.com/omararida) (community)
- **Security:** Limited permissions
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.00 / 1,000 job postings

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

## Career Site Jobs API – jobs straight from company career pages, with salaries

Get every open role from any company's **own career site**, normalized into one clean schema, with **salary ranges extracted**, keyword and location filters, and a **monitoring mode** that returns only the jobs posted since your last run.

It works by talking to the public JSON endpoints behind the applicant-tracking systems companies use, so there is no fragile scraping, no CAPTCHAs and no proxies. Supported ATS:

| ATS | Example source |
| --- | --- |
| Greenhouse | `https://boards.greenhouse.io/stripe` or `greenhouse:stripe` |
| Lever | `https://jobs.lever.co/spotify` or `lever:spotify` |
| Ashby | `https://jobs.ashbyhq.com/openai` |
| Workable | `https://apply.workable.com/acme` |
| SmartRecruiters | `https://careers.smartrecruiters.com/Visa` |
| **Workday** | `https://nvidia.wd5.myworkdayjobs.com/NVIDIAExternalCareerSite` |
| **Oracle Recruiting Cloud** | `https://xyz.fa.em2.oraclecloud.com/hcmUI/CandidateExperience/en/sites/CX_1` |

You can also paste a normal company careers page (e.g. `https://www.example.com/careers`) and the Actor will look for the embedded ATS link, or a bare slug (`stripe`) and it will try Greenhouse, Lever and Ashby.

### What people use it for

- **Recruiters & sourcers** – watch 200 target companies and get a daily feed of new openings in your niche.
- **Sales teams** – hiring is a buying signal. "Who is hiring NetSuite / SAP / Salesforce / Kubernetes people right now?" = companies that are about to buy related services.
- **Compensation analysts & HR tech** – posted salary ranges (now required by pay-transparency laws in many US states and EU countries) normalized into min / max / currency / period.
- **Job boards & aggregators** – a reliable, structured feed from employers' primary sources.
- **Analysts & journalists** – headcount trends, remote-vs-office shifts, new office locations.
- **AI agents** – clean structured input via the Apify MCP server.

### Input

```json
{
    "sources": ["https://boards.greenhouse.io/stripe", "https://jobs.lever.co/spotify", "https://jobs.ashbyhq.com/openai"],
    "keywords": ["NetSuite", "SAP", "ERP"],
    "locationKeywords": ["London", "Remote"],
    "includeDescription": true,
    "onlyNewSinceLastRun": true,
    "monitorKey": "erp-hiring-watch"
}
```

| Field | Description | Default |
| --- | --- | --- |
| `sources` | Career-site URLs, ATS board URLs, `ats:slug` or bare slugs | – |
| `keywords` | Keep jobs whose title/department/description contains any of these | all |
| `excludeKeywords` | Drop jobs containing any of these | – |
| `locationKeywords` | Keep jobs whose location contains any of these | all |
| `remoteOnly` | Only remote roles | `false` |
| `postedWithinDays` | Only jobs posted in the last N days | no limit |
| `includeDescription` | Fetch full description (needed for description keyword matching and text salary extraction) | `true` |
| `onlyNewSinceLastRun` | Monitoring mode – output only jobs not returned before under the same `monitorKey` | `false` |
| `monitorKey` | Name of the watchlist memory | `default` |
| `maxJobsPerSource`, `maxJobs` | Safety caps | 5000 / 100000 |

### Output

One record per job:

```json
{
    "ats": "greenhouse",
    "sourceSlug": "stripe",
    "company": "Stripe",
    "jobId": "6123456",
    "title": "Senior Accountant, Revenue",
    "department": "Finance",
    "team": null,
    "location": "Dublin, IE",
    "locations": ["Dublin, IE"],
    "isRemote": false,
    "employmentType": "Full-time",
    "postedAt": "2026-10-21T09:12:00Z",
    "updatedAt": "2026-10-28T11:03:00Z",
    "applyUrl": "https://boards.greenhouse.io/stripe/jobs/6123456",
    "salary": { "min": 95000, "max": 120000, "currency": "EUR", "period": "year", "source": "text", "raw": "€95,000 - €120,000 per year" },
    "descriptionText": "Who we are…",
    "isNew": true,
    "firstSeenAt": "2026-10-29T20:00:00Z"
}
```

`salary.source` is `structured` when the ATS publishes a pay range (Lever, Ashby, Greenhouse pay-range metadata) and `text` when it was parsed from the description. `SUMMARY` in the key-value store lists, per source, how many jobs were fetched, matched and new, plus any source that failed.

Download as JSON, CSV or Excel, or query the dataset through the API.

### Monitoring mode

Turn on **onlyNewSinceLastRun**, give the watchlist a `monitorKey`, and add an Apify **Schedule** (e.g. every morning). Each run returns only jobs you have not seen before, so you can pipe them to Slack, email, a Google Sheet or your CRM with an Apify integration. Memory is stored in a key-value store named `career-site-jobs-api-state` in your account; delete the key to reset.

### Pricing

Pay per event: a small amount **per job delivered** plus a start fee. You only pay for jobs that pass your filters. In monitoring mode you only pay for the new ones. Set a max cost per run in the Console to stay in control.

### API / agents

```bash
curl "https://api.apify.com/v2/acts/omararida~career-site-jobs-api/run-sync-get-dataset-items?token=<APIFY_TOKEN>" \
  -X POST -H 'Content-Type: application/json' \
  -d '{"sources":["greenhouse:stripe"],"keywords":["accountant"],"includeDescription":false}'
```

Works with the [Apify MCP server](https://mcp.apify.com) so Claude, ChatGPT and other agents can call it as a tool.

### Notes

- Workable and SmartRecruiters descriptions require one extra request per job; turn off `includeDescription` for faster list-only runs.
- Salary extraction from free text is heuristic. It is tuned for ranges like `$120,000 - $150,000`, `€4.500 – €5.500 per month`, `AED 15,000 – 20,000 monthly`, `£45k-55k`, `$45 - $60 / hour`. Always keep the `raw` field for audit.
- Only public job boards are read. No personal data is collected.

### Support

Missing an ATS (iCIMS, SuccessFactors, Taleo, BambooHR, Personio, Recruitee, Teamtailor)? Open an issue on the **Issues** tab with an example career page and it will be added.

# Actor input Schema

## `sources` (type: `array`):

One per line. Accepts career-page URLs (https://boards.greenhouse.io/stripe, https://jobs.lever.co/netflix, https://jobs.ashbyhq.com/openai, https://apply.workable.com/acme, https://careers.smartrecruiters.com/Visa, https://nvidia.wd5.myworkdayjobs.com/NVIDIAExternalCareerSite, https://xyz.fa.em2.oraclecloud.com/hcmUI/CandidateExperience/en/sites/CX_1), shorthand like greenhouse:stripe, a bare slug (tries Greenhouse, Lever, Ashby), or any company careers page – the Actor looks for the embedded ATS.

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

Only keep jobs whose title, department or description contains at least one of these (case-insensitive). E.g. NetSuite, SAP, "data engineer". Leave empty for all jobs.

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

Drop jobs containing any of these.

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

Keep jobs whose location contains any of these, e.g. London, Dubai, United States, Remote.

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

Keep only jobs flagged or described as remote.

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

Drop jobs older than this (when the ATS exposes a posting date). 0 = no limit.

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

Fetch and include the full description (plain text, max ~6,000 chars). Needed for keyword matching inside descriptions and for salary extraction from text. Slightly slower.

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

Remembers the jobs it has already returned (per Monitor key) and outputs only newly posted ones. Schedule the Actor daily to get a feed of new openings.

## `monitorKey` (type: `string`):

Name of the memory used by monitoring mode. Use different keys for different watchlists.

## `maxJobsPerSource` (type: `integer`):

Safety cap per career site.

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

Safety cap on jobs delivered (and charged).

## Actor input object example

```json
{
  "sources": [
    "https://boards.greenhouse.io/stripe",
    "https://jobs.lever.co/spotify",
    "https://jobs.ashbyhq.com/openai"
  ],
  "keywords": [],
  "excludeKeywords": [],
  "locationKeywords": [],
  "remoteOnly": false,
  "postedWithinDays": 0,
  "includeDescription": true,
  "onlyNewSinceLastRun": false,
  "monitorKey": "default",
  "maxJobsPerSource": 5000,
  "maxJobs": 100000
}
```

# Actor output Schema

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

No description

## `summary` (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 = {
    "sources": [
        "https://boards.greenhouse.io/stripe",
        "https://jobs.lever.co/spotify",
        "https://jobs.ashbyhq.com/openai"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("omararida/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 = { "sources": [
        "https://boards.greenhouse.io/stripe",
        "https://jobs.lever.co/spotify",
        "https://jobs.ashbyhq.com/openai",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("omararida/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 '{
  "sources": [
    "https://boards.greenhouse.io/stripe",
    "https://jobs.lever.co/spotify",
    "https://jobs.ashbyhq.com/openai"
  ]
}' |
apify call omararida/career-site-jobs-api --silent --output-dataset

```

## MCP server setup

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