# Workable Jobs Scraper & API: Daily New-Job Feed (`deftcell/workable-jobs-api`) Actor

Scrape every public job from Workable careers pages (apply.workable.com) as clean JSON: all locations, remote flags, departments, employment type, dates, apply links, and plain-text descriptions. Give account names, URLs, careers pages, or domains. Incremental mode returns only new jobs.

- **URL**: https://apify.com/deftcell/workable-jobs-api.md
- **Developed by:** [Ervin Amaya](https://apify.com/deftcell) (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.05 / 1,000 job delivereds

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?

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

## Workable Jobs Scraper & API: Daily New-Job Feed

**Workable jobs scraper and API.** Scrape **every public job posting from any Workable careers page** (apply.workable.com) into clean, structured JSON: title, department, all locations, remote flag, employment type, dates, apply link, and a plain-text description. It reads Workable's public accounts endpoint: no login, no API key, no browser.

Give it account names (`huggingface`), careers URLs, company careers pages, or bare domains. Turn on **incremental mode** and each scheduled run returns only jobs you haven't received yet: a ready-made daily Workable job feed for job boards, recruiting tools, sales signals, market research, and AI agents.

**Built and maintained by an AI agent operated by Elite Tech Global LLC (Deftcell).** Issues are monitored and answered by the same AI-assisted team.

> Need Greenhouse, Lever, or Ashby too? [ATS Jobs API](https://apify.com/deftcell/ats-jobs-api) reads all four in one run with the same output schema. This edition is the same engine, focused on Workable.

### What this Workable jobs scraper does

- **Reads Workable's public accounts endpoint**, the one Workable documents for companies building their own careers page. No login, no API key, no browser.
- **Company name included.** Workable publishes the account's display name, so `companyName` is filled without extra input.
- **Every visible location.** All of a job's locations are returned as "City, Region, Country". Locations the company marked hidden are left out, so a job whose locations are all hidden has an empty `locations` list.
- **Remote flag** from Workable's own telecommuting field: `isRemote: true` and `workplaceType: "remote"` when the company marked the job remote.
- **Pay ranges only when stated.** Workable's public endpoint carries no structured salary. A salary *range* is taken from the description only when it's clearly stated next to words like "salary", "base", or "pay", and every salary says where it came from (`salarySource`, `salaryText`). Most Workable postings have none, and nothing is guessed.
- **Board finder.** Pass `https://example.com/careers` or `example.com` and the Actor looks for the company's Workable link on that one page.
- **Filters:** keywords, locations, remote only, "posted within N days", and a per-company cap. Filtered-out jobs are not charged.
- **Incremental mode** for daily feeds, with one memory per `feedName`.
- **Polite and reliable:** at most 5 requests in flight, robots.txt (including Crawl-delay) honoured, retries with backoff on 429/5xx, timeouts on every request.

### How to scrape Workable jobs: input examples

**Account names (the simplest input):**

```json
{ "companies": ["huggingface", "flosum"] }
```

**URLs, careers pages, and domains:**

```json
{
  "companies": [
    "https://apply.workable.com/huggingface/",
    "https://www.workable.com/api/accounts/flosum",
    "https://www.example.com/careers"
  ],
  "maxJobsPerCompany": 100
}
```

**Remote engineering jobs from the last two weeks:**

```json
{
  "companies": ["huggingface", "flosum"],
  "keywords": ["engineer", "developer"],
  "remoteOnly": true,
  "postedWithinDays": 14
}
```

**Daily feed of new jobs only (pair it with an Apify schedule):**

```json
{
  "companies": ["huggingface", "flosum"],
  "incremental": true,
  "feedName": "daily-workable-feed"
}
```

#### Input fields

| Field | Type | Default | Description |
|---|---|---|---|
| `companies` | array (required) | – | Workable account names, careers or API URLs, company careers-page URLs, domains, or `{ "ats": "workable", "token", "companyName" }` objects. Up to 10,000 per run. |
| `keywords` | string\[] | `[]` | Keep jobs whose title or department contains any keyword. Whole words, case-insensitive; `engineer` also matches "Engineering". |
| `keywordsInDescription` | boolean | `false` | Also search the description text. |
| `locations` | string\[] | `[]` | Keep jobs matching any location: city, region, country, or `Remote`. `US`/`USA`/`United States` are treated as the same place. |
| `remoteOnly` | boolean | `false` | Keep only jobs with `isRemote: true`. |
| `postedWithinDays` | integer | none | Keep jobs whose `postedAt` is within this many days. |
| `maxJobsPerCompany` | integer | none | Deliver at most this many jobs per company, newest first. |
| `includeDescriptionHtml` | boolean | `false` | Add the original description HTML (`descriptionHtml`). Plain text is always included. |
| `incremental` | boolean | `false` | Deliver only jobs not delivered by earlier runs with the same `feedName`. |
| `feedName` | string | `"default"` | Name of the feed whose memory is used. |

### Output: Workable job data as JSON, CSV, or Excel

One dataset item per job, in the same schema as [ATS Jobs API](https://apify.com/deftcell/ats-jobs-api). A real posting read on 2026-10-07, description shortened:

```json
{
  "id": "7ec11e07721b5b6af6b36bf9",
  "ats": "workable",
  "companyToken": "huggingface",
  "companyName": "Hugging Face",
  "atsJobId": "81B46579FE",
  "title": "Open-Source Machine Learning Engineer - EMEA Remote",
  "department": "Open Source",
  "team": null,
  "employmentType": "FULL_TIME",
  "employmentTypeRaw": "Full-time",
  "locations": [
    "Paris, Île-de-France, France"
  ],
  "isRemote": true,
  "workplaceType": "remote",
  "salaryMin": null,
  "salaryMax": null,
  "salaryCurrency": null,
  "salaryPeriod": null,
  "salarySource": null,
  "salaryText": null,
  "postedAt": "2026-05-29T00:00:00.000Z",
  "updatedAt": null,
  "applyUrl": "https://apply.workable.com/j/81B46579FE/apply",
  "jobUrl": "https://apply.workable.com/j/81B46579FE",
  "descriptionText": "At Hugging Face, we're on a journey to democratize good AI. We are building the fastest growing platform for AI builders …",
  "companyInput": "huggingface",
  "scrapedAt": "2026-10-07T20:40:02.687Z"
}
```

- `id` is stable across runs (a hash of ATS + board + job ID), so you can de-duplicate or upsert on it.
- `companyToken` always holds the Workable account name; `companyName` is Workable's display name unless you pass your own.
- `team` and `updatedAt` are always `null` for Workable: its public endpoint doesn't publish them.
- `postedAt` is the publish date Workable shows (a date, without a time of day).
- `jobUrl` is the Workable posting page and `applyUrl` is its application form.
- Personal e-mail addresses in descriptions are replaced with `[email removed]`.

The dataset's **Overview** tab shows company, title, locations, workplace, type, salary, posted date, and job link. Export as JSON, CSV, Excel, or through the API.

Each run also saves `RUN_SUMMARY` in its key-value store: one record per input with its `status` (`ok`, `no_jobs`, `no_matching_jobs`, `no_new_jobs`, `duplicate`, `board_not_found`, `not_detected`, `robots_disallowed`, `unsupported_ats`, `invalid_input`, `error`, and the charge-limit statuses), the board it resolved to, and job counts.

### Daily feed of new Workable jobs (incremental mode)

1. Set `incremental: true` and pick a `feedName`, such as `"daily-feed"`.
2. Create an [Apify schedule](https://docs.apify.com/platform/schedules) that runs the Actor (or a saved task) every day.
3. The **first run delivers every matching job.** Later runs deliver only jobs no earlier run with the same `feedName` delivered.

Delivered job IDs are stored per board in a named key-value store in your Apify account, `workable-jobs-api-incremental`. It's separate from ATS Jobs API's store, so a feed's memory doesn't carry over between the two Actors. A job counts as seen only once it is actually delivered. IDs of removed jobs are forgotten after 180 days. Don't run two incremental runs with the same `feedName` at the same time. To start a feed over, use a new `feedName`.

### How much does the Workable Jobs API cost?

Pay per event: **$1.50 per 1,000 jobs delivered** ($0.0015 per job) on Apify's Free plan, and $1.35, $1.20, or $1.05 per 1,000 on Starter, Scale, or Business-and-higher plans (Apify Store discounts), plus Apify's small automatic start event per run. Final prices are on the Actor's pricing tab. Jobs removed by filters, jobs already delivered in incremental mode, boards on other ATSs, and companies that fail are never charged. Set a **maximum charge per run** to cap spend.

### Workable Jobs API for AI agents and MCP clients

- **Smallest useful input:** `{"companies": ["huggingface"], "maxJobsPerCompany": 20}`.
- **API:** `POST https://api.apify.com/v2/actors/deftcell~workable-jobs-api/run-sync-get-dataset-items?token=<APIFY_TOKEN>&maxTotalChargeUsd=1` with the input JSON as the body.
- **MCP:** add `https://mcp.apify.com?tools=deftcell/workable-jobs-api` to your MCP client ([Apify MCP docs](https://docs.apify.com/integrations/mcp)).

### FAQ: Workable job scraping

**Why did a company return no jobs?** Check `RUN_SUMMARY`. `not_detected`: no Workable link was found on the page you gave; pass the account name or URL. `board_not_found`: Workable has no public account with that name. An account can also exist but have 0 open postings (`no_jobs`). `unsupported_ats`: the company uses another ATS; use [ATS Jobs API](https://apify.com/deftcell/ats-jobs-api).

**How do I find a company's account name?** Open one of its job posts or its careers page on Workable. The account name is the part after `apply.workable.com/` (or before `.workable.com`). Or just pass the company's careers page.

**Why is `locations` empty for some jobs?** The company marked every location of that job as hidden in Workable, and hidden locations are not output.

**Can it scrape LinkedIn, Indeed, or arbitrary sites?** No. It reads only Workable's public accounts endpoint, plus the single careers page you give it for detection.

### Data source and compliance

- Jobs come only from Workable's **public accounts endpoint** (`workable.com/api/accounts/<account>`), which Workable documents for building careers pages. No data is taken from behind a login.
- The output contains **job postings, not people.** Recruiter and contact fields are never output, and personal e-mail addresses are removed. Role mailboxes such as `careers@` stay.
- **robots.txt is respected** for every host, including Crawl-delay. Requests are rate-limited and identified by the user agent `DeftcellJobsAPI/1.0 (+https://apify.com/deftcell)`.
- You are responsible for how you use the data, including the hiring companies' terms and applicable privacy law.
- Not affiliated with or endorsed by Workable. The name only describes where the data comes from.

### Related Deftcell Actors

Same engine and output schema, different ATS. Each Actor keeps its own incremental memory.

- [ATS Jobs Scraper & API](https://apify.com/deftcell/ats-jobs-api): Greenhouse, Lever, Ashby, and Workable in one run, with auto-detection from careers pages.
- [Greenhouse Jobs Scraper & API](https://apify.com/deftcell/greenhouse-jobs-api): Greenhouse job boards.
- [Lever Jobs Scraper & API](https://apify.com/deftcell/lever-jobs-api): Lever job sites, EU-hosted sites included.
- [Ashby Jobs Scraper & API](https://apify.com/deftcell/ashby-jobs-api): Ashby job boards (jobs.ashbyhq.com).

### Support

Open an issue on the **Issues** tab with your run ID and what you expected. **Built and maintained by an AI agent operated by Elite Tech Global LLC (Deftcell).**

# Actor input Schema

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

One entry per company. Accepted forms:

- Account name: "huggingface" (the part after apply.workable.com/)
- Careers URL: https://apply.workable.com/flosum/, https://<account>.workable.com, or an API URL (workable.com/api/accounts/<account>)
- Company careers page or domain: https://example.com/careers or example.com (the Actor fetches that one page, respecting robots.txt, and looks for a Workable link)
- Object: {"ats": "workable", "token": "huggingface", "companyName": "Hugging Face"}
  Boards on other ATSs are reported in RUN_SUMMARY and never charged; use deftcell/ats-jobs-api for Greenhouse, Lever, and Ashby.

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

Keep jobs whose title, department, or team contains any of these words or phrases (case-insensitive, whole words; "engineer" also matches "Engineering"). Leave empty to keep all jobs.

## `keywordsInDescription` (type: `boolean`):

When on, keywords also match the job description text (useful for skills such as "Kubernetes").

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

Keep jobs whose location matches any entry, for example "London", "United States", "Germany", or "Remote". "US" and "UK" also match their full names, and US jobs listed as "City, ST" count as United States.

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

Keep only jobs the ATS or the posting marks as remote.

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

Keep only jobs first published within this many days (uses the posting date from the ATS). Leave empty for no limit.

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

Deliver at most this many jobs per company, newest first. Leave empty for all jobs.

## `includeDescriptionHtml` (type: `boolean`):

Add the original description HTML in `descriptionHtml`. Plain text (`descriptionText`) is always included.

## `incremental` (type: `boolean`):

When on, each run delivers only jobs that earlier runs with the same feed name have not delivered yet. The first run delivers everything that matches. Ideal for scheduled daily feeds.

## `feedName` (type: `string`):

Name of the feed whose memory to use, such as `daily-design-jobs`. Use a different name for each separate feed or schedule. Leave empty to use the feed named `default`. (Formerly `incrementalKey`, which still works.)

## Actor input object example

```json
{
  "companies": [
    "huggingface",
    "https://apply.workable.com/flosum/",
    {
      "ats": "workable",
      "token": "huggingface",
      "companyName": "Hugging Face"
    }
  ],
  "keywordsInDescription": false,
  "remoteOnly": false,
  "maxJobsPerCompany": 50,
  "includeDescriptionHtml": false,
  "incremental": false
}
```

# Actor output Schema

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

Normalized job postings (one item per job) in the default dataset.

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

Per-company status, detection method and job counts (RUN_SUMMARY record).

# 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": [
        "huggingface",
        "https://apply.workable.com/flosum/"
    ],
    "maxJobsPerCompany": 50
};

// Run the Actor and wait for it to finish
const run = await client.actor("deftcell/workable-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 = {
    "companies": [
        "huggingface",
        "https://apply.workable.com/flosum/",
    ],
    "maxJobsPerCompany": 50,
}

# Run the Actor and wait for it to finish
run = client.actor("deftcell/workable-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 '{
  "companies": [
    "huggingface",
    "https://apply.workable.com/flosum/"
  ],
  "maxJobsPerCompany": 50
}' |
apify call deftcell/workable-jobs-api --silent --output-dataset

```

## MCP server setup

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