# Career Page Jobs API — Personio, Workable, Greenhouse, Lever +3 (`nefes-tools/eu-company-jobs`) Actor

Get every open job from the career pages of the companies you track — Personio, Workable, Recruitee, Teamtailor, Greenhouse, Lever and Ashby — in one clean table: title, department, location, remote/hybrid, salary when published, date and apply link. Only-new mode for daily job alerts. Pay per job.

- **URL**: https://apify.com/nefes-tools/eu-company-jobs.md
- **Developed by:** [Erich Michal Sikora](https://apify.com/nefes-tools) (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 $1.00 / 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.

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 Page Jobs API — Personio, Workday, Workable, Greenhouse, Lever +4

**Paste the career pages of the companies you care about and get all their open jobs in one clean table.**
Works with the 8 applicant tracking systems most European and US companies use: **Personio, Workday, Workable,
Recruitee, Teamtailor, Greenhouse, Lever and Ashby**. Every job comes with title, department, location,
remote/hybrid/on-site, salary when the company publishes it, date posted and the apply link. Turn on
"Only new jobs", schedule it daily, and you have a job alert for any list of companies. **$1 per 1,000 jobs.**

| You give | You get, per job |
|---|---|
| `https://acme.jobs.personio.de`, `https://apply.workable.com/acme`, `greenhouse:airbnb`, `lever:palantir` … | company, title, department, team, location, city, country, remote/hybrid/on-site, employment type, seniority, salary min/max/currency, posted date, job link, apply link, clean description |

### Who uses it

- **Recruiters and staffing agencies:** watch 50 or 500 target companies and see new openings the day they go live.
- **Job boards and newsletters:** fill a niche board (remote EU engineering, climate tech, fintech in Berlin…) straight from
  the source instead of copying from LinkedIn.
- **Sales teams (hiring signals):** a company that opens 10 sales roles is growing — a warm lead for software, office,
  relocation or HR tools.
- **Market and salary research:** compare roles, locations and published salary ranges across companies.
- **AI agents and automations:** flat JSON with stable fields for Sheets, Airtable, Slack, Make, Zapier or your own app.

### Supported career pages

| System | Link looks like | Short form |
|---|---|---|
| Personio | `https://acme.jobs.personio.de` (or `.com`) | `personio:acme` |
| Workday | `https://acme.wd5.myworkdayjobs.com/External_Career_Site` | — (paste the full link) |
| Workable | `https://apply.workable.com/acme` | `workable:acme` |
| Recruitee | `https://acme.recruitee.com` | `recruitee:acme` |
| Teamtailor | `https://acme.teamtailor.com` | `teamtailor:acme` |
| Greenhouse | `https://boards.greenhouse.io/acme`, `job-boards.eu.greenhouse.io/acme` | `greenhouse:acme` |
| Lever | `https://jobs.lever.co/acme`, `jobs.eu.lever.co/acme` | `lever:acme` |
| Ashby | `https://jobs.ashbyhq.com/acme` | `ashby:acme` |

**Company on its own domain?** Open one job and look where the "Apply" button leads, or at the page source — you will
usually find `personio`, `recruitee`, `greenhouse`, `lever`… plus the company id. Then use the short form, e.g. `recruitee:bunq`.
For **Workday**, just copy the career site link straight from the browser's address bar (e.g. `salesforce.wd12.myworkdayjobs.com/External_Career_Site`);
large employers are listed up to 1,000 open postings per run.

### Filters

- **Keywords** in the job title (optionally also in the description) and **exclude keywords** (`intern`, `werkstudent`).
- **Locations:** any text — `Berlin`, `Germany`, `DE`, `Remote`.
- **Workplace:** remote only, remote or hybrid, hybrid, on-site (where the company states it).
- **Departments / teams**, **posted within N days**, **max jobs per company**, **max jobs in total**.
- **Only new jobs since the last run** — remembers what you already got; you pay only for new jobs.

### Example row

```json
{
  "ats": "recruitee",
  "company": "bunq",
  "title": "Technology Risk Officer",
  "department": "Risk, Legal & Compliance",
  "employmentType": "fulltime_permanent",
  "seniority": "experienced",
  "workplaceType": "hybrid",
  "remote": false,
  "location": "Amsterdam, Noord-Holland, Netherlands",
  "city": "Amsterdam",
  "country": "Netherlands",
  "countryCode": "NL",
  "salaryMin": null,
  "salaryMax": null,
  "postedAt": "2026-09-25T12:31:29.000Z",
  "url": "https://careers.bunq.com/o/technology-risk-officer-1",
  "applyUrl": "https://careers.bunq.com/o/technology-risk-officer-1/c/new",
  "description": "At bunq, we're on a mission to Make Life Easy for our users…"
}
```

Ashby, Lever and Recruitee jobs often include **salary ranges** (`salaryMin`, `salaryMax`, `salaryCurrency`, `salaryPeriod`,
`salaryText`). Fields a system does not publish are `null`.

### Pricing

Pay per event: **$0.001 per job delivered** ($1 per 1,000) plus a tiny start fee. Filtered-out jobs, jobs you already got
in "only new" mode and companies that could not be read cost nothing. Set a maximum cost per run and the Actor stops exactly there.

Typical run: 3 companies, ~170 jobs, under 10 seconds.

### How it works — and what it doesn't do

- Uses only the **public job feeds** these systems publish for career pages and job widgets (Personio XML feed,
  Workday's own career-site search API, Workable widget API, Recruitee careers API, Teamtailor RSS, Greenhouse Job Board
  API, Lever Postings API, Ashby Job Postings API). No login, no browser, no proxies.
- Reads each host's **robots.txt** and respects it. SmartRecruiters is not supported because its robots.txt
  does not allow automated access.
- If a site answers with an **anti-bot check**, the Actor does not try to get around it; the company is skipped and
  reported in the run summary.
- **No personal data:** recruiter e-mails, phone numbers and links to personal profiles (LinkedIn, X, Calendly…) are
  removed from descriptions; application forms, applicant data and recruiter contact fields are never collected.

### Run summary

The `SUMMARY` record in the key-value store lists every company with jobs found, delivered, filtered out, already seen,
and the reason if a career page could not be read (wrong id, not found, robots.txt, anti-bot check).

### Tips

- One run can cover hundreds of companies. Group them by use case and give each schedule its own **memory name** so
  "only new" keeps separate histories.
- Want only fresh jobs without the memory? Use **posted within 1 day** on a daily schedule.
- Missing a system you need? Open an issue on the Actor page.

# Actor input Schema

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

One per line. Paste the company's career page link, e.g. https://acme.jobs.personio.de, https://apply.workable.com/acme, https://acme.recruitee.com, https://acme.teamtailor.com, https://boards.greenhouse.io/acme, https://jobs.lever.co/acme, https://jobs.ashbyhq.com/acme, https://acme.wd5.myworkdayjobs.com/External\_Career\_Site. If a company uses its own domain, write system:company, e.g. recruitee:bunq or greenhouse:airbnb (not for Workday — paste its full career site link).

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

Keep jobs whose title contains any of these words (case-insensitive), e.g. engineer, sales, marketing. Empty = all jobs.

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

Drop jobs whose title contains any of these words, e.g. intern, werkstudent.

## `searchInDescription` (type: `boolean`):

Match keywords in the job description too, not only in the title.

## `locations` (type: `array`):

Keep jobs whose location contains any of these, e.g. Berlin, Germany, DE, Remote. Empty = all locations.

## `workplace` (type: `string`):

Filter by remote / hybrid / on-site where the company states it.

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

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

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

Only jobs published in the last N days (where the career page publishes the date). Empty = any date.

## `onlyNew` (type: `boolean`):

Remember delivered jobs and return only new ones on the next run. Schedule the Actor daily for a job alert. You pay only for new jobs.

## `stateKey` (type: `string`):

Use different names to keep separate memories for different searches.

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

Plain-text job description (emails, phone numbers and personal profile links are removed).

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

Empty = no limit (Workday career sites are listed up to 1000 postings per run regardless).

## `maxResults` (type: `integer`):

Stop after this many jobs.

## Actor input object example

```json
{
  "companies": [
    "https://personio.jobs.personio.de",
    "https://apply.workable.com/huggingface",
    "greenhouse:airbnb"
  ],
  "searchInDescription": false,
  "workplace": "any",
  "onlyNew": false,
  "stateKey": "default",
  "includeDescription": true,
  "maxResults": 1000
}
```

# 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 = {
    "companies": [
        "https://personio.jobs.personio.de",
        "https://apply.workable.com/huggingface",
        "greenhouse:airbnb"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("nefes-tools/eu-company-jobs").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": [
        "https://personio.jobs.personio.de",
        "https://apply.workable.com/huggingface",
        "greenhouse:airbnb",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("nefes-tools/eu-company-jobs").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": [
    "https://personio.jobs.personio.de",
    "https://apply.workable.com/huggingface",
    "greenhouse:airbnb"
  ]
}' |
apify call nefes-tools/eu-company-jobs --silent --output-dataset

```

## MCP server setup

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

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/VlVP2byg1j2ZBBhha/builds/2IJ7n1DTsnfTDglci/openapi.json
