Ashby Job Board Postings - Company Jobs, Pay, Remote
Pricing
from $0.70 / 1,000 job row writtens
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.
Pricing
from $0.70 / 1,000 job row writtens
Rating
0.0
(0)
Developer
Samat Makatov
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
4 days ago
Last modified
Categories
Share
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.
Need it tailored to your workflow? Missing a field, a filter, another source or a different output format? Open an issue and describe what you need — we read every request and adapt the actor.
Use cases
- Watch the hiring of companies you care about: run a list of boards on a schedule with
sinceHoursandonlyNewand 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
titleKeywordsandlocationContains, and publish the rows with their apply links. - Benchmark published pay:
withCompensationOnlyplus the parsedsalaryMin/salaryMax/salaryCurrency/salaryIntervalturn pay-transparency ranges into a table you can average. - Find remote roles across a shortlist:
remoteOnlyuses the employer's own flag, andworkplaceTypesthe field the company set on the posting — no guessing from location text. - Feed postings to a model:
includeDescriptionadds the full description as plain text and as HTML, ready for screening, skill extraction or matching. - Fill a CRM or lead pipeline:
postedWithinDaysanswers "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 |
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 |
employmentTypes | string[] | all | FullTime, PartTime, Intern, Contract, Temporary — see 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 — one memory per saved task, see Scheduling |
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 |
maxItems | integer | 25 | Hard ceiling on the rows of a run, marker rows included, 1–5000. With several boards these are the first rows of one sort across all of them |
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. boardName and found are always kept. A near miss (titel) or another letter case is corrected and a name that is no column is left out — both are named in the status message; when no name is a column the run stops before any request. Naming a description column switches includeDescription on |
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 it tried, because then nothing
is known about any of the names — and such a run writes no row, so it costs only the start event. After three boards in
a row without an answer the remaining boards are not tried; the status message and SUMMARY.boardsNotRead name them.
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 — the form offers them as Full time, Part time, Internship,
Contract and Temporary. Through the API send exactly these values: the platform checks the list before the run starts
and refuses any other spelling ("full time", "full-time") with the list of allowed values.
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 of that board when it is obviously a typo
("Enginering" → "Engineering", or "Software Engineering" on a board that only has that); when nothing is close the value
is kept as typed. Both cases are named in the run's status message (
departments: "Enginering" read as "Engineering" on Rampno department or team contains "Revenue" on Linear) and in SUMMARY.filterCorrections /
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 of every row written, in a named key-value store of your
account, 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.
- One memory per saved task. Run the actor from a saved task (that is what a schedule usually starts) and the task
keeps its own memory (store
ashby-job-postings-state-<task id>), so two schedules on the same board with different filters no longer hide postings from each other. A task's first run starts from what earlier runs of the actor delivered, so nothing comes twice after an upgrade. Runs started without a task (Console, API) share one memory (storeashby-job-postings-state). - Only what was really written is remembered. Rows cut by
maxItems, by your max cost per run or by the run timeout are not remembered and come with the next run. - Marker rows come once. With
onlyNew, the row of a board name the API does not serve and the row of a board without postings are written once, not on every run; a board the API did not answer for is reported by every run in which that happens. - Two runs of the same task that start at the same moment read the same memory — schedule them one after another.
Examples
Engineering roles at one employer
{ "boardNames": ["Ramp"], "titleKeywords": ["engineer"], "sortBy": "publishedDesc", "maxItems": 20 }
Remote roles across a shortlist of companies
{ "boardNames": ["Linear", "elevenlabs", "Modal"], "remoteOnly": true, "maxItemsPerBoard": 8, "maxItems": 24 }
Published pay ranges for a salary benchmark
{ "boardNames": ["Ramp", "Vanta"], "withCompensationOnly": true, "maxItems": 20 }
Revenue-side roles, department and team
{ "boardNames": ["Vanta", "elevenlabs"], "departments": ["Revenue"], "maxItems": 20 }
What appeared in the last 90 days (hiring signal)
{ "boardNames": ["Linear", "elevenlabs", "Vanta"], "postedWithinDays": 90, "maxItems": 20 }
Full posting text for a model
{ "boardNames": ["Sierra"], "includeDescription": true, "maxItems": 5 }
UK roles, secondary locations included
{ "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}
(the errorCode column was added on 2026-10-02; it is null on every posting row):
{"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,"errorCode": 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 (errorCode added on 2026-10-02):
{"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.","errorCode": "board-not-found","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. Always kept, whatever fields lists |
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 or did not answer for. Always kept, whatever fields lists |
error | string | on marker rows | Why a board produced no postings |
errorCode | string | on marker rows | board-not-found (the API answered 404), board-empty (the board publishes nothing right now; found stays true) or board-unreachable (no usable answer: timeout, 5xx, throttling, a block) |
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, the reason in error and errorCode: "board-not-found"; a real board without open roles gives one row
with found: true, postingsOnBoard: 0, its own error text and errorCode: "board-empty"; a board the API did not
answer for while others did gives found: false and errorCode: "board-unreachable". All keep the columns of a
posting row, so the dataset stays one table; they come after the postings and count against maxItems. Marker rows do
not fail the run: check found / errorCode in your code instead of the run status. With onlyNew the first two kinds
are written once, not on every run.
SUMMARY. The key-value store of a run holds a SUMMARY record (linked from the run's output as summary):
boards requested, served, without postings, not served, unreadable, emptied by the filters (boardsEmptiedByFilters:
no posting passed the filters), cut by the row limit (boardsCutByLimit: postings passed but none fitted into
maxItems or your max cost per run), already delivered (boardsAlreadyDelivered, onlyNew) and not read
(boardsNotRead with the reason); the per-board counts (postingsOnBoard, matched, fresh, written), the filters
as they were applied, every correction (corrections, filterCorrections), filtersWithoutMatch, sort order, limits,
the onlyNew store, delivered, stoppedBy (limit, timeout or aborted when the run was cut short), 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
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}'
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();
from apify_client import ApifyClientclient = 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. The start event is charged once per GB of run memory, at least once — once at the default
256 MB. Nothing else is charged, and maxItems is the hard ceiling on what a run can cost. Your maximum cost per
run is respected too: the run writes only the rows it pays for and ends with the status
Stopped at your spending limit: N rows delivered| 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: falserow. - 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;
withCompensationOnlythen returns nothing, which is an honest empty result and not an error. Ranges can be hourly or monthly — always readsalaryIntervalbefore 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.
maxItemsdoes 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. WithincludeDescription, the rows that wait for the cross-board sort keep their descriptions compressed in a temporary file rather than in memory: 30 boards with 2,779 postings and descriptions ran in the default 256 MB (cloud runRELo8R4ZkNKjzTNE2, 134 s — writing rows with descriptions takes most of that, roughly 20 rows a second). - Run timeout. Boards are read one after another and the rows are written once every board is read (the order is
one sort across all of them). Near the run timeout the actor stops starting new boards, writes what it has read and
ends as succeeded with
Stopped before the run timeout: N rows saved; the boards it did not read are named in the status and inSUMMARY.boardsNotRead. A request is never allowed to run past that point. With the default 15-minute timeout this matters only for long board lists — split those, or raise the timeout. - Unreachable source. After three boards in a row without an answer the remaining boards are not tried; the run keeps what it read and names the rest. If no board answered at all, the run fails and writes nothing.
- 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 · hh-kz-vacancies · github-repo-intel · google-news-search · rss-to-json