Ashby Jobs API: how to get every open role from any Ashby job board (jobs.ashbyhq.com) as JSON

Ashby exposes a public Posting API for every company that hosts its job board on jobs.ashbyhq.com. No key, no login. This repository documents the endpoint, the fields, and ships a dependency-free Python example.

The endpoint

GET https://api.ashbyhq.com/posting-api/job-board/{job_board_name}
GET https://api.ashbyhq.com/posting-api/job-board/{job_board_name}?includeCompensation=true

job_board_name is the slug in the board URL: https://jobs.ashbyhq.com/notion → notion. Companies embedding the board on their own domain still use the same name; look for jobs.ashbyhq.com/<name> in the page source.

What you get back

{"apiVersion": "1", "jobs": [...]}. Each job:

Field Example Notes
id 8f6c... UUID, stable; diff between runs
title Product Engineer
department Engineering
team Core
location San Francisco primary location
secondaryLocations[] [{"location":"New York"}]
isRemote true explicit remote flag
employmentType FullTime / PartTime / Contract / Intern
publishedAt 2026-10-20T15:04:05.000Z ISO 8601 UTC
jobUrl, applyUrl https://jobs.ashbyhq.com/notion/<id>
descriptionHtml, descriptionPlain full description
compensation {"compensationTierSummary": "$180K – $220K"...} only with includeCompensation=true and only where published

Pagination and limits

No pagination: the whole board comes back in one response. No published rate limit; cache and keep request rates low.

Python example (stdlib only)

import json, urllib.request

def ashby_jobs(board):
    url = f"https://api.ashbyhq.com/posting-api/job-board/{board}?includeCompensation=true"
    req = urllib.request.Request(url, headers={"User-Agent": "your-app/1.0 (contact@example.com)"})
    with urllib.request.urlopen(req, timeout=30) as r:
        data = json.load(r)
    for j in data["jobs"]:
        yield {"id": j["id"], "title": j["title"], "department": j.get("department"), "team": j.get("team"),
               "location": j.get("location"), "remote": j.get("isRemote"), "type": j.get("employmentType"),
               "url": j["jobUrl"], "posted_at": j.get("publishedAt"),
               "comp": (j.get("compensation") or {}).get("compensationTierSummary")}

if __name__ == "__main__":
    rows = list(ashby_jobs("notion")); print(len(rows), "jobs"); print(rows[0])

Finding Ashby boards

Search site:jobs.ashbyhq.com. Ashby is common among 2020s startups (Notion, Linear, Supabase, Cursor, Ramp and others).

Common questions

Is there a GraphQL endpoint too? The board UI uses an internal GraphQL API; the Posting API above is the public, documented one and is what you should use.

Why is compensation missing? The company has not enabled public compensation on the posting, or you omitted includeCompensation=true.

Hosted version, pay per result

If you would rather not run and maintain this yourself, the same logic runs as a pay-per-result Apify Actor by CleanFeeds: https://apify.com/cleanfeedsapi/ashby-jobs-api ($1.50 per 1,000 rows, no subscription, JSON/CSV/Excel export, API, scheduling, n8n/Make/Zapier and MCP integrations). A multi-ATS variant that mixes Greenhouse, Lever, Ashby, Workday, SmartRecruiters and Recruitee boards in one run: https://apify.com/cleanfeedsapi/ats-jobs-feed

Free sample data: a daily snapshot of about 10,000 open roles at 26 tech companies from these endpoints, CC BY 4.0: https://huggingface.co/datasets/cleanfeeds/tech-jobs-daily

More feeds: https://cleanfeeds.dev

These are public, unauthenticated endpoints that the career pages themselves load. Job postings are employer announcements and belong to the employers. Be polite: identify your client with a User-Agent, cache results, and do not hammer the endpoints. Nothing here is affiliated with or endorsed by Ashby.