# Ashby Job Board Postings - Company Jobs, Pay, Remote (`yadroo/ashby-job-postings`) Actor

Open roles from any Ashby-hosted job board, read through Ashby's documented public posting API - keyless, no browser. One row per posting: title, department, team, location plus every secondary location, remote flag, workplace type, employment type, pay range, published date and apply link.

- **URL**: https://apify.com/yadroo/ashby-job-postings.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 $0.70 / 1,000 job row writtens

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

## Ashby Job Board Postings - Company Jobs, Pay, Remote

Open roles from any Ashby-hosted job board, read through Ashby's documented public posting API - keyless, no browser. One row per posting: title, department, team, location plus every secondary location, remote flag, workplace type, employment type, pay range, published date and apply link.

Give it the companies you follow — `Ramp`, `Linear`, `Vanta`, `elevenlabs` — and every open posting of their boards comes
back as a flat row: job title, department and team, the location the employer typed, all secondary locations of a role
that is open in several countries, the remote flag and workplace type, employment type, the published pay range parsed
into numbers, the publication time in UTC and the links to the posting and to its application form. No API key, no
proxy and no browser: one plain HTTPS request per board, filtered and sorted here.

### Use cases

- **Watch the hiring of companies you care about**: run a list of boards on a schedule with `sinceHours` and `onlyNew`
  and the dataset holds only the roles that went live since the last run — the hiring signal behind account research.
- **Build a niche job board**: take a shortlist of employers, keep the roles that match `titleKeywords` and
  `locationContains`, and publish the rows with their apply links.
- **Benchmark published pay**: `withCompensationOnly` plus the parsed `salaryMin` / `salaryMax` / `salaryCurrency` /
  `salaryInterval` turn pay-transparency ranges into a table you can average.
- **Find remote roles across a shortlist**: `remoteOnly` uses the employer's own flag, and `workplaceTypes` the field
  the company set on the posting — no guessing from location text.
- **Feed postings to a model**: `includeDescription` adds the full description as plain text and as HTML, ready for
  screening, skill extraction or matching.
- **Fill a CRM or lead pipeline**: `postedWithinDays` answers "which of my target accounts started hiring" with the
  department, country and job link in the same row.

### Input

Only `boardNames` is required. Filters are combined with AND, the values inside one filter with OR.

| Field | Type | Default | Allowed values / notes |
|---|---|---|---|
| `boardNames` | string\[] | required | Ashby boards, e.g. `["Ramp", "Linear"]`. The name is the segment in `jobs.ashbyhq.com/<board>`; the whole address (with or without a posting id) works too. Case does not matter. One request per board |
| `titleKeywords` | string\[] | all | Keep a posting when its title contains one of these words, case-insensitive |
| `excludeTitleKeywords` | string\[] | none | Drop a posting whose title contains one of these words. Applied after `titleKeywords` |
| `departments` | string\[] | all | Keep postings whose department **or** team contains one of these. Labels are each company's own — see [Departments and teams](#departments-and-teams) |
| `locationContains` | string\[] | all | Keep postings whose location wording contains one of these. Searched over the primary location, every secondary location and the city, region and country of the address — the `locationsText` column of a row is exactly that text |
| `workplaceTypes` | string\[] | all | `Remote`, `Hybrid`, `OnSite` — see [Workplace types](#workplace-types) |
| `employmentTypes` | string\[] | all | `FullTime`, `PartTime`, `Intern`, `Contract`, `Temporary` — see [Employment types](#employment-types) |
| `remoteOnly` | boolean | `false` | Keep only postings the employer marked remote (`isRemote`) |
| `withCompensationOnly` | boolean | `false` | Keep only postings with a published pay range. Needs `includeCompensation` on |
| `postedWithinDays` | integer | no limit | Published in the last N days, 1–365, counted in UTC |
| `sinceHours` | integer | no limit | Published in the last N hours, 1–8760, counted in UTC |
| `onlyNew` | boolean | `false` | Write only postings that were not delivered by an earlier run of this actor — see [Scheduling](#scheduling-with-onlynew) |
| `includeDescription` | boolean | `false` | Add `descriptionText` and `descriptionHtml` to every row |
| `includeCompensation` | boolean | `true` | Ask the API for pay and fill the salary columns |
| `includeUnlisted` | boolean | `false` | Also write postings whose `isListed` is false (kept off the company's board page) |
| `sortBy` | string | `publishedDesc` | `publishedDesc`, `publishedAsc`, `titleAsc`, `boardOrder` — see [Sort orders](#sort-orders) |
| `maxItems` | integer | `25` | Hard ceiling on the rows of a run, 1–5000 |
| `maxItemsPerBoard` | integer | no cap | Rows taken from each board before the global ceiling, 1–2000 |
| `fields` | string\[] | all | Keep only these output fields, in this order |

### Reference

#### Board names

A company's Ashby board lives at `jobs.ashbyhq.com/<board>` — `Ramp`, `Vanta`, `Linear`, `elevenlabs`, `Sierra`,
`Modal`. Copy that last segment, or paste the whole address of the board or of a single posting; the name is taken out
of it. Upper and lower case lead to the same board; Ashby echoes the case you asked with, so the `company`
column and the posting links keep your spelling (`RAMP` stays `RAMP`) — compare board names case-insensitively. A name Ashby does not serve comes back as one row with `found: false` and the run still ends as succeeded —
even when that was the only name asked for, so a typo in a scheduled run never turns the schedule red. A company that
hires elsewhere simply has no Ashby board. A run fails only if the API itself stays unreachable for every board, because
then nothing is known about any of the names.

#### Workplace types

| Token | What the employer means |
|---|---|
| `Remote` | The role is not tied to an office |
| `Hybrid` | Office and home, usually with a home base |
| `OnSite` | On location |

The field is optional on Ashby: many postings leave it empty, and those are never swept into a `workplaceTypes`
filter. `remoteOnly` is a separate flag on the posting — a hybrid role can carry it too, so use `workplaceTypes` when
you want strictly remote-first roles.

#### Employment types

`FullTime`, `PartTime`, `Intern`, `Contract`, `Temporary`. Write them as Ashby spells them; "full time", "full-time"
and an obvious typo are corrected for you and the correction is logged in the run status.

#### Departments and teams

Ashby carries two levels and every company invents its own labels: Vanta files roles under the department `Revenue`
with teams `Sales Development` and `Account Executives`, Linear uses `GTM` and `Product`, elevenlabs
`Engineering & Product`. `departments` searches both levels, so `["Sales Development"]` finds the team inside
`Revenue`. To see what a board uses, run it once without filters and read the `department` and `team` columns. A value
that no label of the board contains is corrected to the closest label when it is obviously a typo ("Enginering" →
"Engineering"); when nothing is close the value is kept as typed and reported in `SUMMARY.filtersWithoutMatch`, so a
filter never quietly returns more than you asked for.

#### Sort orders

| Value | Order |
|---|---|
| `publishedDesc` | Newest publication first (default) |
| `publishedAsc` | Oldest publication first |
| `titleAsc` | Job title A–Z |
| `boardOrder` | The order the board returns |

With several boards the rows are ordered across all of them, after `maxItemsPerBoard` was applied.

#### Scheduling with onlyNew

`onlyNew` remembers board, posting id and publication time in a key-value store of this actor and writes only what was
not delivered before. The first run returns everything it finds; a posting taken down and published again counts as
new, because its publication time moved. Combine it with `sinceHours` on a schedule to keep runs small.

### Examples

**Engineering roles at one employer**

```json
{ "boardNames": ["Ramp"], "titleKeywords": ["engineer"], "sortBy": "publishedDesc", "maxItems": 20 }
```

**Remote roles across a shortlist of companies**

```json
{ "boardNames": ["Linear", "elevenlabs", "Modal"], "remoteOnly": true, "maxItemsPerBoard": 8, "maxItems": 24 }
```

**Published pay ranges for a salary benchmark**

```json
{ "boardNames": ["Ramp", "Vanta"], "withCompensationOnly": true, "maxItems": 20 }
```

**Revenue-side roles, department and team**

```json
{ "boardNames": ["Vanta", "elevenlabs"], "departments": ["Revenue"], "maxItems": 20 }
```

**What appeared in the last 90 days (hiring signal)**

```json
{ "boardNames": ["Linear", "elevenlabs", "Vanta"], "postedWithinDays": 90, "maxItems": 20 }
```

**Full posting text for a model**

```json
{ "boardNames": ["Sierra"], "includeDescription": true, "maxItems": 5 }
```

**UK roles, secondary locations included**

```json
{ "boardNames": ["elevenlabs", "Linear"], "locationContains": ["United Kingdom"], "maxItems": 20 }
```

### Output

One row per posting. A real row from the cloud run `nG6mfs3wiP9SLeZa4` (2026-09-25) with
`{"boardNames": ["Ramp", "Vanta"], "includeCompensation": true, "withCompensationOnly": true, "sortBy": "publishedDesc", "maxItems": 20}`:

```json
{
  "boardName": "Ramp",
  "company": "Ramp",
  "jobId": "72c3ef8f-e390-4ee1-9c0d-83b7b616ee17",
  "title": "Principal Brand Designer",
  "department": "Design",
  "team": "Design",
  "employmentType": "FullTime",
  "location": "New York, NY (HQ)",
  "secondaryLocations": [],
  "locationsText": "New York, NY (HQ) | New York City | NY | USA",
  "city": "New York City",
  "region": "NY",
  "country": "USA",
  "isRemote": true,
  "workplaceType": "Hybrid",
  "isListed": true,
  "publishedAt": "2026-09-25T21:05:27.698Z",
  "hasSalary": true,
  "salaryMin": 200000,
  "salaryMax": 275000,
  "salaryCurrency": "USD",
  "salaryInterval": "year",
  "compensationSummary": "$200K - $275K",
  "compensationDetails": "$200K – $275K • Offers Equity",
  "offersEquity": true,
  "offersCommission": false,
  "url": "https://jobs.ashbyhq.com/Ramp/72c3ef8f-e390-4ee1-9c0d-83b7b616ee17",
  "applyUrl": "https://jobs.ashbyhq.com/Ramp/72c3ef8f-e390-4ee1-9c0d-83b7b616ee17/application",
  "postingsOnBoard": 157,
  "found": true,
  "error": null,
  "sourceUrl": "https://api.ashbyhq.com/posting-api/job-board/Ramp?includeCompensation=true",
  "fetchedAt": "2026-09-25T22:54:36.041Z"
}
```

A board name Ashby serves nothing for produces one marker row instead, and the run stays successful — cloud run
`b0tkqRVVnf0ebWCX3` with `{"boardNames": ["Rmap"], "maxItems": 5}` ended as succeeded with the status line
`0 posting(s) from 0 of 1 board(s) · no board served for Rmap` and one row. It carries the same columns as a posting
row with the posting fields left null; the columns that say what happened are:

```json
{
  "boardName": "Rmap",
  "company": null,
  "title": null,
  "postingsOnBoard": 0,
  "found": false,
  "error": "no Ashby job board is served for \"Rmap\" (the API answered 404). Open the company's job page and copy the name from jobs.ashbyhq.com/<board> — a company that does not hire through Ashby has no board at all.",
  "sourceUrl": "https://api.ashbyhq.com/posting-api/job-board/Rmap?includeCompensation=true",
  "fetchedAt": "2026-09-25T22:54:53.604Z"
}
```

| Field | Type | Always filled | Meaning |
|---|---|---|---|
| `boardName` | string | yes | The board as you asked for it |
| `company` | string | for `found: true` | The board name, taken from the posting link — in the case you requested it (Ashby echoes it) |
| `jobId` | string | for postings | Ashby posting id (the last segment of the job link) |
| `title` | string | for postings | Job title as published |
| `department` | string | usually | The department the company filed the role under |
| `team` | string | usually | The narrower team inside the department |
| `employmentType` | string | usually | `FullTime`, `PartTime`, `Intern`, `Contract`, `Temporary` |
| `location` | string | for postings | The primary location text the employer typed |
| `secondaryLocations` | string\[] | when the role is open in several places | Every further location of the posting |
| `locationsText` | string | for postings | All location wordings of the posting joined with `\|` — the text `locationContains` searches |
| `city` | string | when the address has one | `addressLocality` of the posting address |
| `region` | string | when the address has one | State or region of the posting address |
| `country` | string | usually | Country of the posting address, as the employer wrote it ("USA", "United States") |
| `isRemote` | boolean | when the employer set it | The remote flag of the posting, `null` when it was left empty |
| `workplaceType` | string | when the employer set it | `Remote`, `Hybrid` or `OnSite` |
| `isListed` | boolean | for postings | Whether the posting is shown on the company's board page |
| `publishedAt` | string | for postings | First publication, ISO 8601 UTC |
| `hasSalary` | boolean | yes | Whether a pay range was published for this posting |
| `salaryMin` | number | when published | Lower end of the range, whole currency units |
| `salaryMax` | number | when published | Upper end of the range |
| `salaryCurrency` | string | when published | ISO currency code, e.g. `USD`, `GBP`, `SEK` |
| `salaryInterval` | string | when published | `year`, `month`, `hour` — never assumed, always the employer's |
| `compensationSummary` | string | when published | The range as the board shows it, e.g. `$224K - $263K` |
| `compensationDetails` | string | when published | The full pay line incl. equity, bonus and benefit notes |
| `offersEquity` | boolean | yes | Equity is part of the package |
| `offersCommission` | boolean | yes | Commission is part of the package |
| `descriptionText` | string | with `includeDescription` | The posting text, tags stripped |
| `descriptionHtml` | string | with `includeDescription` | The description as published |
| `url` | string | for postings | The posting page on `jobs.ashbyhq.com` |
| `applyUrl` | string | for postings | The application form of the posting |
| `postingsOnBoard` | number | yes | How many postings the board serves in total (before filters) |
| `found` | boolean | yes | `false` only on the marker row of a board the API does not serve |
| `error` | string | on marker rows | Why a board produced no postings |
| `sourceUrl` | string | yes | The API address the row came from |
| `fetchedAt` | string | yes | When the board was read, ISO 8601 UTC |

**Marker rows.** A run never ends silently empty. A board name the API does not serve gives one row with
`found: false` and the reason in `error`; a real board without open roles gives one row with `found: true`,
`postingsOnBoard: 0` and its own `error` text. Both keep the columns of a posting row, so the dataset stays one table,
and both count against `maxItems`. Marker rows do not fail the run: check `found` in your code instead of the run status.

**SUMMARY.** The key-value store of a run holds a `SUMMARY` record: boards requested, served, without postings,
not served and emptied by the filters, the per-board counts (`postingsOnBoard`, `matched`, `written`), the filters as
they were applied, filter corrections, sort order, limits, the number of requests and the run's status line.

Dataset views: **Open postings** (the overview columns), **Published pay** (range, currency, interval, equity) and
**Recently published** (what is new, with country, employment type and apply link).

### Use it from code / agents

```bash
curl -X POST "https://api.apify.com/v2/acts/yadroo~ashby-job-postings/run-sync-get-dataset-items?token=$APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"boardNames":["Ramp"],"titleKeywords":["engineer"],"maxItems":20}'
```

```js
import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('yadroo/ashby-job-postings').call({
    boardNames: ['Ramp', 'Vanta'],
    withCompensationOnly: true,
    fields: ['company', 'title', 'salaryMin', 'salaryMax', 'salaryCurrency', 'url'],
    maxItems: 50,
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
```

```python
from apify_client import ApifyClient
client = ApifyClient(os.environ["APIFY_TOKEN"])
run = client.actor("yadroo/ashby-job-postings").call(run_input={
    "boardNames": ["Linear", "elevenlabs"],
    "sinceHours": 24,
    "onlyNew": True,
    "maxItems": 50,
})
items = client.dataset(run["defaultDatasetId"]).list_items().items
```

MCP: add `https://mcp.apify.com` to Claude / Cursor / any MCP client and call the `yadroo/ashby-job-postings` tool with
the same JSON input. For an agent, keep `includeDescription` off until you really need the text — rows are about twenty
times larger with it — and cut the row down with `fields` to the columns your prompt reads.

### Pricing

Pay per event: **$0.001 per run start + $0.001 per dataset row**. A row is one posting — or the marker row of a board
that returned nothing. Nothing else is charged, and `maxItems` is the hard ceiling on what a run can cost.

| Run | Cost |
|---|---|
| 25 rows (the default) | $0.026 |
| 50 rows | $0.051 |
| 500 rows | $0.501 |

Apify's paid plans discount every tier: Bronze −10 %, Silver −20 %, Gold and above −30 % on the per-row price; the
start event stays flat. A 50-row run on Gold therefore costs $0.001 + 50 × $0.0007 = $0.036.

### Limits & FAQ

- **Coverage is per company.** Ashby has no cross-company search, so this actor reads the boards you name. Companies
  that use another applicant-tracking system have no Ashby board at all — the run says so in a `found: false` row.
- **No "changed since".** Ashby publishes the first publication time only, so every time window here
  (`postedWithinDays`, `sinceHours`) is about when a posting appeared, never about when it was last edited.
- **Locations and departments are free text.** Countries come out as the employer typed them ("United States", "USA",
  "US", "European Union"), and department labels differ per company. Match on the words a company would write, and read
  a board's own labels once before filtering.
- **Pay is published by the employer.** Many boards publish no ranges at all; `withCompensationOnly` then returns
  nothing, which is an honest empty result and not an error. Ranges can be hourly or monthly — always read
  `salaryInterval` before averaging.
- **Large boards are slow.** Descriptions are always part of the API response, so a board with a few hundred roles
  answers with several megabytes even when descriptions are not written out. `maxItems` does not make the download smaller, because the whole list comes in one response. The largest board
  measured while building this actor served 829 postings in 14.5 MB and was read inside 256 MB of memory in four
  seconds, so big boards cost time, not failures.
- **Unlisted roles** are only written with `includeUnlisted`; by default the output matches what a visitor of the
  board sees.
- **Rate limits.** Ashby documents none for this endpoint. The actor sends one request per board, retries politely on
  429 and 5xx and honours `Retry-After`. If the source ever puts the posting API behind a key, this actor is paused
  rather than worked around.
- **Which boards exist?** Ashby has no directory. Open a company's careers page: if its job links point to
  `jobs.ashbyhq.com`, the segment after the host is the board name.

***

Made by **Yadroo**. Sibling actors:
[greenhouse-jobs](https://apify.com/yadroo/greenhouse-jobs) ·
[hh-kz-vacancies](https://apify.com/yadroo/hh-kz-vacancies) ·
[github-repo-intel](https://apify.com/yadroo/github-repo-intel) ·
[google-news-search](https://apify.com/yadroo/google-news-search) ·
[rss-to-json](https://apify.com/yadroo/rss-to-json)

# Actor input Schema

## `boardNames` (type: `array`):

One or more Ashby job boards, e.g. `Ramp`, `Linear`, `Vanta`, `elevenlabs`. The board name is the segment after the host in a company's job page URL (`jobs.ashbyhq.com/<board>`) - paste the whole URL and the name is taken out of it. One request per board, no pagination. A board name the API does not serve comes back as a single row with `found: false` and the run still ends as succeeded, so a typo never fails the whole run - not even when it was the only name given.

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

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

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

Drop a posting when its title contains any of these words, e.g. \["intern", "director"]. Applied after `titleKeywords`.

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

Keep postings whose department or team contains one of these, case-insensitive, e.g. \["Revenue", "Engineering"]. Ashby carries both levels: companies name the department ("Revenue", "Software Engineering") and often a narrower team ("Sales Development", "EMEA Engineering"), and each company invents its own labels - see the README on reading a board's own labels first.

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

Keep postings whose location text, any secondary location, or the city / region / country of the posting's address contains one of these, e.g. \["United Kingdom", "Berlin", "Europe"]. Location strings come from the employer, so country spellings differ between boards ("United States", "USA", "US"); match on the words a company would write.

## `workplaceTypes` (type: `array`):

Keep postings with one of these workplace types, spelled as Ashby stores them (`Remote`, `Hybrid`, `OnSite`). It is a real field per posting, so this filter does not guess from location text. Not every employer fills it in; empty = all types, filled or not.

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

Keep postings with one of these employment types, as Ashby labels them. Empty = all types.

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

Keep only postings that the employer marked remote (`isRemote` in the API). Combined with `workplaceTypes` by AND: a hybrid posting can also carry the remote flag, so use the workplace type when you want strictly remote-first roles.

## `withCompensationOnly` (type: `boolean`):

Keep only postings that publish compensation. Pay is published per posting, mostly by employers under US, EU or UK disclosure rules, so a whole board can be without ranges. Needs `includeCompensation` on (the default).

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

Keep postings first published in the last N days (UTC) - the "who started hiring recently" filter for hiring-signal and lead pipelines. Empty = no age limit.

## `sinceHours` (type: `integer`):

Keep postings published inside the last N hours (UTC). Made for schedules: run it every few hours and the dataset holds only what appeared since. Empty = no limit.

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

Remember board name, job id and `publishedAt` in this actor's key-value store and write only rows that were not there on the previous run. The first run writes everything it finds. A posting that is taken down and published again counts as new because its `publishedAt` moved.

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

Add `descriptionText` (tags stripped, entities decoded, blank lines kept) and `descriptionHtml` (as published) to every row. The API always sends descriptions, so this only decides whether they are written; rows become roughly 20x larger with them.

## `includeCompensation` (type: `boolean`):

Ask the API for compensation and fill `salaryMin`, `salaryMax`, `salaryCurrency`, `salaryInterval`, `compensationSummary`, `offersEquity` and `offersCommission`. Off makes the response smaller for big boards.

## `includeUnlisted` (type: `boolean`):

Also write postings whose `isListed` is false - roles the company keeps off its public board page. Off by default so the output matches what visitors of the board can see.

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

Order of the rows. With several boards the rows are sorted across all of them, after `maxItemsPerBoard` was applied.

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

Stop after this many rows in total. A typical Ashby board has 5-100 open postings; the largest ones a few hundred.

## `maxItemsPerBoard` (type: `integer`):

Cap the rows taken from each board before the global `maxItems`, so one heavy employer cannot fill the whole dataset when you watch a list of companies. Empty = no per-company cap.

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

Keep only these output fields, in this order, e.g. \["company", "title", "location", "url"]. Empty = all fields.

## Actor input object example

```json
{
  "boardNames": [
    "Ramp",
    "Linear"
  ],
  "remoteOnly": false,
  "withCompensationOnly": false,
  "onlyNew": false,
  "includeDescription": false,
  "includeCompensation": true,
  "includeUnlisted": false,
  "sortBy": "publishedDesc",
  "maxItems": 25
}
```

# 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 = {
    "boardNames": [
        "Ramp",
        "Linear"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("yadroo/ashby-job-postings").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 = { "boardNames": [
        "Ramp",
        "Linear",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("yadroo/ashby-job-postings").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 '{
  "boardNames": [
    "Ramp",
    "Linear"
  ]
}' |
apify call yadroo/ashby-job-postings --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,yadroo/ashby-job-postings"
        }
    }
}
```

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/qwAs96QB85ARZJWvi/builds/CPAB8hRBaQAHwAGws/openapi.json
