# Ashby Jobs API

> Query jobs from Ashby job boards through one API — and how Ashby's posting endpoint, compensation tiers and isRemote flag really behave.

Source: https://hyperjobs.io/ats/ashby

Ashby is an all-in-one recruiting platform that's become the default at a lot of
newer, engineering-heavy startups. Boards live at `jobs.ashbyhq.com/<name>`, and
the public posting API returns an entire board — descriptions and structured
compensation included — in a single unauthenticated GET. Alongside
[Greenhouse](/ats/greenhouse) it's the nicest ATS in this pool to read, and it
publishes better salary data than any of them.

## Try it

```bash
curl -G https://api.hyperjobs.io/v1/jobs \
  -H "Authorization: Bearer $HYPERJOBS_KEY" \
  --data-urlencode "source=ashby" \
  --data-urlencode "has_salary=true" \
  --data-urlencode "limit=2"
```

```json title="Illustrative — the shape, not a live response"
{
  "data": [
    {
      "id": "ashby:7c1f2a94-3e17-4d8b-9c05-1f6ab2e40d33",
      "title": "Staff Backend Engineer",
      "company": {
        "slug": "meridian",
        "name": "Meridian",
        "domain": "meridian.dev",
        "website": "https://meridian.dev",
        "logo": "https://media.licdn.com/dms/image/…",
        "industry": "Software Development",
        "employee_count": 95
      },
      "location": {
        "remote": true,
        "countries": ["United States"],
        "cities": ["New York"],
        "regions": ["NY"],
        "raw": ["New York, NY, USA"]
      },
      "employment_type": ["FULL_TIME"],
      "work_arrangement": "Remote",
      "salary": {
        "min": 191000,
        "max": 291000,
        "currency": "USD",
        "unit": "YEAR",
        "annual_min": 191000,
        "annual_max": 291000,
        "summary": "$191K - $291K"
      },
      "skills": ["typescript", "postgresql", "kubernetes"],
      "taxonomies": ["Software"],
      "apply_url": "https://jobs.ashbyhq.com/meridian/7c1f2a94-3e17-4d8b-9c05-1f6ab2e40d33/application",
      "url": "https://jobs.ashbyhq.com/meridian/7c1f2a94-3e17-4d8b-9c05-1f6ab2e40d33",
      "source": "ashby",
      "posted_at": "2026-07-11T13:45:00.000Z",
      "expires_at": null,
      "updated_at": "2026-07-14T02:15:40.000Z"
    }
  ],
  "total": 2,
  "limit": 2,
  "offset": 0
}
```

## How Ashby boards actually work

One GET, no auth, no pagination, whole board with bodies:

```bash
curl "https://api.ashbyhq.com/posting-api/job-board/<name>?includeCompensation=true"
```

`<name>` is the board name from `jobs.ashbyhq.com/<name>`. Response is
`{ "jobs": [...] }`. Each posting carries `id` (a UUID), `title`,
`descriptionHtml` (real HTML, not entity-escaped), `publishedAt` as ISO,
`jobUrl`, `applyUrl`, `department`, `team`, `employmentType`, `location`,
`address`, `secondaryLocations[]`, `isListed`, `isRemote`, `workplaceType`, and —
if you asked for it — `compensation`.

`includeCompensation=true` is opt-in and free. Leave it off and you silently get
no pay data at all.

### Compensation is genuinely structured

Ashby is the best salary source in this pool, and the reason is that it publishes
typed components rather than a string:

```json
"compensation": {
  "compensationTiers": [
    { "components": [
      { "compensationType": "Salary", "interval": "1 YEAR",
        "currencyCode": "USD", "minValue": 191000, "maxValue": 240000 },
      { "compensationType": "EquityCashValue", "interval": "1 YEAR", "minValue": 40000 }
    ] }
  ],
  "scrapeableCompensationSalarySummary": "$191K - $291K"
}
```

Two things follow. **Filter on `compensationType === "Salary"`** — an
`EquityCashValue` or `Commission` component is not base pay, and summing them
gives you a number the employer never offered. And **tiers are geographic**: one
posting can carry a band per market, so the real posted range is the outer band
across every tier — the minimum of the mins, the maximum of the maxes.

`interval` is `"1 YEAR"` or `"1 HOUR"` — a count and a unit in one string, so it
needs normalising before it means anything.

Ashby also ships `scrapeableCompensationSalarySummary`, which is a courtesy: a
pre-rendered `$191K - $291K` explicitly meant to be read by scrapers. It's the
fallback when the typed numbers are absent, and parsing it means anchoring each
number to a currency symbol — otherwise `Multiple Ranges` and stray tier counts
get read as salaries.

### The address is better than the location string

`location` is a display string like `New York, NY (HQ)`. Alongside it, `address.postalAddress`
carries `addressLocality`, `addressRegion` and `addressCountry` as separate
fields. The string often drops the country the structured address keeps, so
preferring the structured form is what makes a bare-city posting resolve.
`secondaryLocations[]` has the same shape for multi-site roles.

## What bites you

<Warning title="`isRemote` is hybrid-inclusive">
  Ashby's `isRemote` boolean reads **true for hybrid roles too**. On some boards
  it's true for roughly 87% of postings. Treat it as "is this remote" and you
  will tag most of a company's on-site-two-days-a-week jobs as fully remote.

  `workplaceType` is the field you want — `Remote`, `Hybrid`, `OnSite`, the real
  three-way. Use `isRemote` only as a fallback when `workplaceType` is absent, and
  never when it's present.
</Warning>

**Some board tokens aren't companies.** Ashby hosts curated multi-company
aggregator boards — "jobs pages" — whose token is `jobs-page-<uuid>` or a bare
UUID. They look exactly like a company board and return real postings, from many
different employers. Scrape one and you attribute dozens of companies' jobs to a
single garbage employer named `Jobs-Page-<uuid>`. We detect and skip those tokens.
If you're building your own board list, this is the trap that quietly poisons your
company table.

**`isListed: false` is in the payload.** Unlisted postings come back with
everything else. Filter them out or you'll publish roles the employer chose not
to show.

**A posting may have `applyUrl` but no `jobUrl`.** Take whichever is present.

## Or use ours

If you have ten known Ashby boards, the endpoint above is the whole job and you
should just use it. This page exists partly to make that easy.

What we add is the surrounding work. We track 4,227 Ashby boards, which is the
hard part — Ashby publishes no customer index, and the aggregator "jobs pages"
mean a naive board list actively harms you. Beyond that: the outer band computed
across compensation tiers, `workplaceType` preferred over the hybrid-inclusive
boolean, expiry by board diffing, dedup against the same role on
[LinkedIn](/ats/linkedin) or [Lever](/ats/lever), and the [company
join](/docs/objects/company) turning a board slug into a profile.

And normalisation. Ashby's `{ compensationType, interval: "1 YEAR", minValue }`,
[Greenhouse](/ats/greenhouse)'s cents, and [Recruitee](/ats/recruitee)'s
string-typed bounds all arrive as one [`salary`](/docs/objects/job) object with
`annual_min` and `annual_max` you can compare. [Salary
data](/docs/guides/salary) is honest about where that breaks down.

Ashby is in the fast refresh tier, attempted every cycle — a new posting usually
lands within the hour. [Coverage](/docs/reference/coverage) has the tiers.

[Quickstart](/docs/quickstart) · [Pricing](/pricing)
