# Workable Jobs by Company: ATS Career Page Postings API (`yadroo/workable-jobs`) Actor

Published jobs of any company hosted on Workable, read through the account's public jobs endpoint: title, department, function, city, state, country, remote flag, employment type, publish date, apply link and optional description. Two extra modes count open jobs per department and per location.

- **URL**: https://apify.com/yadroo/workable-jobs.md
- **Developed by:** [Samat Makatov](https://apify.com/yadroo) (community)
- **Categories:** Jobs, Business, Lead generation
- **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 row returneds

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 by Company: ATS Career Page Postings API

Published jobs of any company hosted on Workable, read through the account's public jobs endpoint: title, department, function, city, state, country, remote flag, employment type, publish date, apply link and optional description. Two extra modes count open jobs per department and per location.

Give it the slugs of the career pages you care about (`devsinc-17`, `prox-works`, `wantable-careers`) and every published opening of those companies comes back as a clean row — company, job title, department, city, region, country, ISO country code, remote flag, employment type, seniority, education, job function, industry, publish date, days online, apply URL, and the full job description on request. The rows come from the employer's own career page, so the company behind a posting is never a guess. Built for recruiters and sourcing agencies watching a list of accounts, for go-to-market teams who treat a new opening as a buying signal, and for job-market researchers. No API key, no login, no browser, no proxy: one keyless request per career page.

### Use cases

- **Sourcing watchlist**: keep the openings of 20–200 target employers in one dataset, refreshed on a schedule; `onlyNew` writes only the postings that appeared since the last run.
- **Hiring signal for B2B sales**: `postedWithinDays: 30` over your account list shows who started hiring — a team that grows is a team with a budget.
- **One job family across many employers**: `titleKeywords: ["engineer"]` plus `excludeTitleKeywords: ["intern"]` turns a list of career pages into a role-specific feed.
- **Remote-only job feed**: `workplace: "remote"` keeps the postings employers marked as remote, ready for a newsletter or a job board.
- **AI screening and keyword audits**: `includeDescription: true` adds the description as HTML and as plain text, so an LLM can score a posting against a profile without a second fetch.
- **Org and market research**: `mode: "departments"` shows which teams a company is growing, `mode: "locations"` which countries it hires in — one row per department or country with its open-job count.

### Input

| Field | Type | Default | Allowed values / notes |
|---|---|---|---|
| `accounts` | string\[] | **required** | Career page slugs, e.g. `["devsinc-17", "prox-works"]`. A whole career page URL works too (`https://apply.workable.com/devsinc-17/`); a link to a single job (`/j/<code>`) is rejected with a message. See [Finding the slug](#finding-the-slug). |
| `mode` | string | `jobs` | `jobs`, `departments`, `locations` — see [Modes](#modes) |
| `titleKeywords` | string\[] | empty | Keep a job when its title contains any of these (case-insensitive) |
| `excludeTitleKeywords` | string\[] | empty | Drop a job when its title contains any of these; applied after `titleKeywords` |
| `departments` | string\[] | empty | Keep jobs whose department contains any of these. Free text per company — `mode: "departments"` prints the exact list |
| `locationContains` | string\[] | empty | Text match over city, region and country of every location of a job |
| `countryCodes` | string\[] | empty | Exact two-letter ISO 3166-1 codes, e.g. `["US", "GB", "PK"]`; `mode: "locations"` prints the codes a page uses |
| `workplace` | string | `any` | `any`, `remote`, `onsite` — from the employer's own remote flag |
| `employmentTypes` | string\[] | empty (all) | [Employment types](#employment-types); setting it drops postings where the employer left the field blank |
| `experienceLevels` | string\[] | empty (all) | [Experience levels](#experience-levels); same rule about blank values |
| `postedWithinDays` | integer | empty (no limit) | 1–3650. Published in the last N days; the source's publish date has **day** resolution |
| `onlyNew` | boolean | `false` | Write only postings that were not delivered by an earlier run of this actor (jobs mode only) |
| `includeDescription` | boolean | `false` | Add `descriptionHtml` and `descriptionText`; same request, no extra source call |
| `sortBy` | string | `publishedDesc` | `publishedDesc`, `publishedAsc`, `titleAsc`, `departmentAsc`, `pageOrder` — see [Sort orders](#sort-orders) |
| `maxItems` | integer | `50` | 1–5000 rows in total, across all career pages |
| `maxItemsPerAccount` | integer | empty (no cap) | 1–2000 rows per career page, applied before `maxItems` |
| `fields` | string\[] | all | Keep only these output fields, in this order |

### Reference

#### Finding the slug

A hosted career page looks like `https://apply.workable.com/<slug>/` — the `<slug>` part is what this actor takes: `apply.workable.com/devsinc-17/` → `devsinc-17`. Companies usually link that page from their own site as "Careers" or "Open positions"; the slug is frequently not the company name (`wantable-careers` for Wantable, `prox-works` for Proximity Works). You may paste the whole URL and the slug is read from it, in any letter case. A link to one posting (`apply.workable.com/j/F9263E6A0E`) contains no slug and is refused with a message instead of being guessed at. A slug the platform does not serve comes back as one row with `found: false` and an explanation, and the run still succeeds.

#### Modes

| `mode` | One row per | Fields you get |
|---|---|---|
| `jobs` | published job | the full job row below; all filters apply |
| `departments` | department of the career page | `name`, `openJobs`, `filterUrl`, `facetType: "department"` |
| `locations` | location of the career page | `name`, `locationCode` (ISO 3166-1 alpha-2), `openJobs`, `facetType: "location"` |

The dictionary modes ignore the job filters — they describe a whole career page. They are the cheapest way to learn the values `departments` and `countryCodes` expect, and a product in themselves: which teams is this employer growing, in which countries does it hire.

#### Employment types

`Full-time`, `Part-time`, `Contract`, `Temporary`, `Internship`, `Other`. This is a closed list: the input schema rejects anything else before the run starts, and the actor reads the values you pass in any letter case (`full-time`, `FULL-TIME`). The field is optional for the employer: on small career pages 10–50 % of postings leave it blank, and those are dropped as soon as you set the filter.

#### Experience levels

`Internship`, `Entry level`, `Associate`, `Mid-Senior level`, `Director`, `Executive`, `Not Applicable`. A closed list and employer-optional, exactly like the employment types above.

#### Sort orders

| `sortBy` | Order |
|---|---|
| `publishedDesc` | newest publish date first (default) |
| `publishedAsc` | oldest publish date first |
| `titleAsc` | job title A–Z |
| `departmentAsc` | department A–Z, then title |
| `pageOrder` | exactly as the career page returns the postings |

Rows are ordered across all career pages of a run, after `maxItemsPerAccount` was applied, so `maxItems` keeps the newest postings of the whole watchlist. In the dictionary modes rows are ordered by open-job count, largest first.

#### Filter semantics

Filters are combined with **AND**, values inside one filter with **OR**: `titleKeywords: ["engineer", "designer"]` with `countryCodes: ["US"]` means "engineer or designer, in the United States". Filtering happens on the complete response of each career page, so nothing is lost to paging. `countryCodes` compares the code of the job's own location record; `locationContains` is a text match over city, region and country, including the extra locations of a multi-location posting. A job without a department cannot satisfy a `departments` filter and is dropped. Because department names are free text each company types itself, a misspelt one is matched against the names that career page really uses (`Enginering` → `Engineering`, written to the log); a value that resembles nothing is kept as typed and the log prints the page's own list. Either way a filter returns fewer rows — it never widens the search.

### Examples

**Every opening of one employer, newest first**

```json
{ "accounts": ["devsinc-17"], "mode": "jobs", "maxItems": 25 }
```

**Remote-only feed from several career pages**

```json
{ "accounts": ["remote-recruitment", "remotebase"], "mode": "jobs", "workplace": "remote", "maxItems": 25 }
```

**Engineering roles across a sourcing watchlist**

```json
{ "accounts": ["prox-works", "devsinc-17", "remotebase"], "mode": "jobs", "titleKeywords": ["engineer"], "excludeTitleKeywords": ["intern"], "maxItems": 20 }
```

**New postings as a hiring signal (last 30 days)**

```json
{ "accounts": ["remote-recruitment", "devsinc-17", "prox-works"], "mode": "jobs", "postedWithinDays": 30, "sortBy": "publishedDesc", "maxItems": 25 }
```

**Full-time United States jobs only**

```json
{ "accounts": ["aetos-systems-inc", "wantable-careers", "scalable"], "mode": "jobs", "countryCodes": ["US"], "employmentTypes": ["Full-time"], "maxItems": 25 }
```

**Job descriptions for an LLM screen**

```json
{ "accounts": ["wantable-careers"], "mode": "jobs", "includeDescription": true, "maxItems": 5 }
```

**Which teams is this company growing**

```json
{ "accounts": ["devsinc-17", "prox-works"], "mode": "departments", "maxItems": 30 }
```

**Where does it hire**

```json
{ "accounts": ["remote-recruitment", "prox-works"], "mode": "locations", "maxItems": 30 }
```

### Output

One real row of a cloud run (input: `{"accounts": ["devsinc-17"], "mode": "jobs", "maxItems": 25}`):

```json
{
  "account": "devsinc-17",
  "companyName": "Devsinc",
  "title": "Functional Consultant",
  "shortcode": "3F21775CBA",
  "requisitionCode": null,
  "department": "Cluster Head",
  "function": "Consulting",
  "industry": "Computer Hardware",
  "experienceLevel": "Mid-Senior level",
  "educationLevel": "Bachelor's Degree",
  "employmentType": "Full-time",
  "isRemote": false,
  "city": "Lahore",
  "region": "Punjab",
  "country": "Pakistan",
  "countryCode": "PK",
  "locationText": "Lahore, Punjab, Pakistan",
  "extraLocations": [],
  "locationCount": 1,
  "publishedOn": "2026-09-25",
  "createdOn": "2024-11-28",
  "daysSincePublished": 1,
  "url": "https://apply.workable.com/j/3F21775CBA",
  "applyUrl": "https://apply.workable.com/j/3F21775CBA/apply",
  "careerPageUrl": "https://apply.workable.com/devsinc-17/",
  "found": true,
  "error": null,
  "fetchedAt": "2026-09-26T20:47:46.177Z"
}
```

| Field | Type | Meaning |
|---|---|---|
| `account` | string | Career page slug that produced the row (always filled) |
| `companyName` | string | Company name as the career page publishes it (always filled) |
| `title` | string | Job title (always filled) |
| `shortcode` | string | The platform's code for the posting, also the last part of `url` (always filled) |
| `requisitionCode` | string | null | The employer's internal code — optional, often empty |
| `department` | string | null | Free-text team name; empty on career pages that use none |
| `function` | string | null | Job function, e.g. `Art/Creative`, `Consulting` — employer-optional |
| `industry` | string | null | Industry of the employer as chosen for the posting — employer-optional |
| `experienceLevel` | string | null | Seniority from the [dictionary](#experience-levels) — employer-optional |
| `educationLevel` | string | null | Required education, e.g. `Bachelor's Degree` — employer-optional |
| `employmentType` | string | null | [Employment type](#employment-types) — employer-optional |
| `isRemote` | boolean | The employer's remote flag (always present; one flag, no hybrid value) |
| `city` | string | null | City of the first location; empty for country-wide postings |
| `region` | string | null | State, province or region of the first location |
| `country` | string | null | Country name of the first location |
| `countryCode` | string | null | ISO 3166-1 alpha-2 code of the first location — what `countryCodes` filters on |
| `locationText` | string | null | `City, Region, Country` of the first location, skipping what is empty |
| `extraLocations` | string\[] | The same text for every further location of the posting (empty for single-location jobs) |
| `locationCount` | number | How many locations the posting lists |
| `publishedOn` | string | null | Publish date, `YYYY-MM-DD` (the source gives no clock time) |
| `createdOn` | string | null | Date the posting was created in the system; can be much older than `publishedOn` |
| `daysSincePublished` | number | null | Whole UTC days since `publishedOn` — what `postedWithinDays` filters on |
| `url` | string | Public job page (`apply.workable.com/j/<shortcode>`) |
| `applyUrl` | string | null | The posting's application page |
| `careerPageUrl` | string | The company's career page |
| `descriptionHtml` | string | null | Job description as the employer published it — only with `includeDescription` |
| `descriptionText` | string | null | The same text with tags removed and entities decoded — only with `includeDescription` |
| `found` | boolean | `false` on the marker row of a career page the platform does not serve |
| `error` | string | null | Why a row is a marker row; `null` on job rows |
| `fetchedAt` | string | When the career page was read, ISO 8601 UTC |

Rows of `mode: "departments"` and `mode: "locations"` carry `account`, `companyName`, `facetType`, `name`, `locationCode` (locations only), `openJobs`, `filterUrl` (the source's own filtered career-page link), `url`, `found`, `error`, `fetchedAt`:

```json
{
  "account": "remote-recruitment",
  "companyName": "Remote Recruitment",
  "facetType": "location",
  "name": "South Africa",
  "locationCode": "ZA",
  "openJobs": 84,
  "filterUrl": "https://apply.workable.com/api/v1/widget/accounts/694803?location=ZA",
  "url": "https://apply.workable.com/remote-recruitment/",
  "found": true,
  "error": null,
  "fetchedAt": "2026-09-26T20:47:53.626Z"
}
```

Dataset views: **Jobs** (company, title, department, city, country, remote, employment type, publish date, days online, job page), **Job details** (function, industry, seniority, education, location text, internal code, apply link), **Departments & locations** (the dictionary modes). `descriptionHtml` and `descriptionText` are in no view on purpose — they would break a table; read them through the API or with `fields`.

Every run also writes a `SUMMARY` record to the default key-value store: per career page how many postings were on the page, how many matched, how many were written, which filter values matched nothing, and the run's status sentence.

### Use it from code / agents

```bash
curl -X POST "https://api.apify.com/v2/acts/yadroo~workable-jobs/run-sync-get-dataset-items?token=$APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"accounts":["devsinc-17","prox-works"],"titleKeywords":["engineer"],"maxItems":20,"fields":["companyName","title","city","countryCode","publishedOn","url"]}'
```

```js
import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('yadroo/workable-jobs').call({ accounts: ['wantable-careers'], includeDescription: true, maxItems: 5 });
const { items } = await client.dataset(run.defaultDatasetId).listItems();
```

```python
from apify_client import ApifyClient
client = ApifyClient(os.environ["APIFY_TOKEN"])
run = client.actor("yadroo/workable-jobs").call(run_input={"accounts": ["devsinc-17"], "postedWithinDays": 7, "maxItems": 25})
items = client.dataset(run["defaultDatasetId"]).list_items().items
```

MCP: add `https://mcp.apify.com` to Claude / Cursor / any MCP client and call the `yadroo/workable-jobs` tool with the same JSON input.

Agent and pipeline tips: use `fields` to keep rows narrow and prompts short; schedule the actor daily with `postedWithinDays: 7` plus `onlyNew: true` so each run writes only postings you have not seen (the memory lives in the actor's own key-value store `workable-jobs-state`, keyed by career page); run `mode: "departments"` once per employer to learn the department names before you filter on them.

### Pricing

Pay per event: **$0.001 per run start + $0.0015 per dataset row**. Every run is charged the start event, also a run that ends with a single `found: false` row. Marker rows count as rows and take their slot inside `maxItems`, so a run never charges for more rows than you asked for. Apify plan discounts apply to both events: −10 % on Bronze, −20 % on Silver, −30 % on Gold and above.

| Run | Rows | Cost at list price |
|---|---|---|
| One career page, 25 newest jobs | 25 | $0.001 + 25 × $0.0015 = **$0.0385** |
| The default input: three career pages, 50 rows | 50 | $0.001 + 50 × $0.0015 = **$0.0760** |
| Daily watchlist of 30 employers, 400 new postings | 400 | $0.001 + 400 × $0.0015 = **$0.6010** |
| Departments of two career pages | 18 | $0.001 + 18 × $0.0015 = **$0.0280** |

`includeDescription` costs nothing extra on the source side — the descriptions arrive in the same request — it only makes the rows about twenty times larger. Compute is negligible: 256 MB and a few seconds per career page, no browser.

### Limits & FAQ

- **Coverage is per career page.** The actor reads the accounts you name; there is no keyword search across all employers and no company discovery, because the platform's cross-company job board disallows crawling its search paths in `robots.txt`. Bring your own list of slugs.
- **Only published jobs.** Drafts, internal and archived postings are not served publicly, and neither are they here.
- **No salary.** This payload carries no pay range or pay-transparency field. `educationLevel` and `experienceLevel` are the closest things to a requirement summary.
- **Publish dates have day resolution.** `publishedOn` is a date without a clock time, so the finest monitoring window is `postedWithinDays: 1`; for a tighter loop schedule the actor with `onlyNew: true`. `createdOn` is when the posting was created in the system and can be years older than the publish date.
- **Employer-optional fields are often empty**: department, function, industry, employment type, seniority, education, internal code. Filter on them to narrow a large board, and expect the blank ones to disappear from the result.
- **One remote flag, no hybrid.** A hybrid role appears as remote or on-site depending on how the employer filled the form.
- **Dictionary counts are the source's own numbers** and can differ from the number of job rows a career page returns (duplicate postings and locations an employer hides are counted differently). Treat `openJobs` as the count the career page shows, not as a row count.
- **Large boards come in one response.** No pagination parameter is documented and boards of up to 249 postings came back complete; `maxItems` cuts the rows, never the request. A career page with thousands of postings is untested — set `maxItemsPerAccount` when you watch a very large employer.
- **Unknown slug vs. empty career page.** A slug the platform does not serve always produces one `found: false` row with an explanation, and the run still succeeds; a career page that exists but publishes nothing right now is reported in the log, the status message and `SUMMARY`, and gets a marker row only when the run would otherwise write nothing. A run fails only when the source answered none of its requests.
- **Rate limits and politeness.** One request per career page per mode, sequential, with retry and backoff on 429 and 5xx. The endpoints are the ones the vendor documents for building a careers page, `robots.txt` allows them, and the actor never touches candidate or application endpoints — no personal data is collected. The site's content signals allow search and AI input but not model training; we read the postings, we do not train on them.
- **If the platform ever puts these endpoints behind a wall**, this actor will be marked paused in the store rather than trying to work around it.

***

Made by **Yadroo**. Sibling actors: [greenhouse-jobs](https://apify.com/yadroo/greenhouse-jobs) (the same job for Greenhouse boards), [hh-kz-vacancies](https://apify.com/yadroo/hh-kz-vacancies) (vacancies in Kazakhstan and the CIS), [github-repo-intel](https://apify.com/yadroo/github-repo-intel), [domain-intel](https://apify.com/yadroo/domain-intel), [sec-company-financials](https://apify.com/yadroo/sec-company-financials) (company research around a hiring signal).

# Actor input Schema

## `accounts` (type: `array`):

One or more Workable account slugs, e.g. `devsinc-17`, `prox-works`, `wantable-careers`. The slug is the part after the host in a hosted career page URL (`apply.workable.com/<slug>/`) — paste the whole career page URL and the slug is taken from it. A link to a single job (`apply.workable.com/j/<code>`) carries no slug and is rejected with a message naming the slug form. Each entry costs one request; a slug the platform does not serve comes back as one row with `found: false` instead of failing the run.

## `mode` (type: `string`):

`jobs` writes a row per published job of every career page. `departments` and `locations` return the same company's own dictionaries with a job count each — the cheap way to see how a company is organised, where it hires, and which values the filters below accept. `jobs` costs one request per career page; the two dictionary modes add a small second one for the company name, because the dictionary endpoints answer a bare list.

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

Keep a job when its title contains at least one of these words, case-insensitive, e.g. \["engineer", "designer"]. Empty = every published job of the career page.

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

Drop a job when its title contains any of these words, e.g. \["intern", "volunteer"]. Applied after *Job title contains any of*.

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

Keep jobs whose department contains one of these, case-insensitive, e.g. \["Engineering", "Sales"]. Departments are free text each company types itself, so run mode `departments` once to see the exact list of a career page. Jobs with no department are dropped by this filter.

## `locationContains` (type: `array`):

Keep jobs whose city, state or country contains one of these, e.g. \["Lahore", "Texas", "India"]. Matched against every location of a job, so a posting open in three cities is kept when one of them matches.

## `countryCodes` (type: `array`):

Keep jobs in these countries by two-letter code, e.g. \["US", "GB", "PK"]. The code comes from the job's own location record, so it is exact where *Location contains any of* is a text match. Mode `locations` lists the codes a career page actually uses.

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

The source carries one remote flag per job (`isRemote` in the output), set by the company. It has no separate hybrid value, so a hybrid job appears as remote or on-site depending on how the employer filled the form.

## `employmentTypes` (type: `array`):

Keep jobs of these employment types. Empty = all types, including jobs where the employer left the field blank; setting any value drops those blank ones, because the type is optional on the platform and many small companies skip it.

## `experienceLevels` (type: `array`):

Keep jobs with these seniority values (`experienceLevel` in the output). Optional on the platform as well: only part of the career pages fill it, so use it to narrow a large board, not as your only filter.

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

Keep jobs first published in the last N days — the "who started hiring recently" filter for hiring-signal and lead pipelines. The source gives the publish date without a clock time, so a day is the finest window it can answer. Empty = no age limit.

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

Remember career page and job code in this actor's key-value store and write only jobs that were not there on the previous run. The first run writes everything it finds, later runs write the openings that appeared since. Use it on a schedule to follow a list of companies without paying for the same rows twice.

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

Add `descriptionHtml` (as the employer published it) and `descriptionText` (tags stripped, entities decoded, blank lines kept) to every job row. The descriptions arrive in the same request, so this costs no extra calls — it only makes rows about twenty times larger, which is why it is off by default.

## `sortBy` (type: `string`):

Order of the rows before *Max rows* cuts the list. With several career pages the rows are sorted across all of them, after *Max rows per career page* was applied. In the dictionary modes the rows are ordered by job count, largest first.

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

Stop after this many rows in total. A small employer publishes 1-10 jobs, a mid-size one 30-100, the largest career pages a few hundred.

## `maxItemsPerAccount` (type: `integer`):

Cap the rows taken from each career page before the global *Max rows*, so one big employer cannot fill the whole dataset when you watch a list of companies. Empty = no per-company cap.

## `fields` (type: `array`):

Keep only these fields, in this order, e.g. \["companyName", "title", "city", "url"]. Empty = every field the mode produces.

## Actor input object example

```json
{
  "accounts": [
    "devsinc-17",
    "prox-works",
    "remote-recruitment"
  ],
  "mode": "jobs",
  "workplace": "any",
  "onlyNew": false,
  "includeDescription": false,
  "sortBy": "publishedDesc",
  "maxItems": 50
}
```

# Actor output Schema

## `results` (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 = {
    "accounts": [
        "devsinc-17",
        "prox-works",
        "remote-recruitment"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("yadroo/workable-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 = { "accounts": [
        "devsinc-17",
        "prox-works",
        "remote-recruitment",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("yadroo/workable-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 '{
  "accounts": [
    "devsinc-17",
    "prox-works",
    "remote-recruitment"
  ]
}' |
apify call yadroo/workable-jobs --silent --output-dataset

```

## MCP server setup

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