Greenhouse Job Board API: how to export jobs and salaries from Greenhouse job boards

Last updated: 27 October 2026 · By Quicksloth

Companies that publish their jobs on Greenhouse have job boards at addresses like job-boards.greenhouse.io/figma. Greenhouse documents a public API for these job boards. It needs no key, and one request returns every published job of a board in JSON. This guide shows what the API returns and what we got when we tried it on two real job boards. It also has a short free script that saves a board as a CSV file, and explains when a scheduled cloud run is the better choice.

Short version: GET https://boards-api.greenhouse.io/v1/boards/<token>/jobs?content=true returns all published jobs of one board, with descriptions and departments. Salaries come only with pay_transparency=true, and only where the employer publishes them.

What the public API offers

Greenhouse calls it the Job Board API (documentation read on 27 October 2026). In Greenhouse's words, it gives "a simple JSON representation of your company's offices, departments, and published jobs", so that companies "can build careers pages with a unique look and feel". The documentation also says: "Job Board data is publicly available, so authentication is not required for any GET endpoints."

The main fields of each job, from the documentation (the full list is on Greenhouse's page):

FieldWhat it holds
id, internal_job_idthe ID of the job post and the ID of the job itself
title, location.namethe job title and the location as one text
updated_atwhen the job was last updated
absolute_urlthe job page, on Greenhouse or on the company's own site
metadatathe custom fields the company chose to show, for example a work type
content, departments, officeswith content=true: the description (HTML encoded as text, for example &lt;p&gt;), departments and offices
pay_input_rangeswith pay_transparency=true: min_cents, max_cents, currency_type and a title such as "Pay Range"

Limits we know of: the documentation states no rate limit, so keep a gentle pace (one request per board, with a pause). Amounts are in cents, and the pay range has no interval field: the period is only in its title, when the employer writes it. Work type is not a standard field: some companies add it in metadata, others write "Remote" in the location. In our test the list also returned company_name and first_published, which the documentation shows only in its single-job example. Boards on job-boards.eu.greenhouse.io are not covered by this guide.

What we got on two real job boards

We called the endpoint with curl on 27 October 2026 for two companies:

curl "https://boards-api.greenhouse.io/v1/boards/figma/jobs?content=true&pay_transparency=true"
BoardJobsResponse size (plain / with content and pay ranges)With a pay rangeWork type
figma14189 KB / 1.8 MB90 (all USD)no work type field
airbnb188145 KB / 2.8 MB152 (USD, EUR, CAD, GBP, MXN, BRL, INR)a Workplace Type custom field: 142 remote, 39 hybrid, 7 on-site

Each request took about a second. Without pay_transparency=true the same Figma request returned no pay ranges. Airbnb's job links point to its own careers site, not to Greenhouse. A board token that does not exist returns HTTP 404 with {"status":404,"error":"Job not found"}.

A free Python script: one board to CSV

The script reads one or more boards and writes greenhouse_jobs.csv with one row per job: company, title, department, location, first published and updated dates, pay range, currency, the title of the pay range and link. It uses only Python's standard library (Python 3.8 or later).

"""Export the jobs of one or more Greenhouse job boards to a CSV file, with salary where the employer publishes it."""
import csv
import json
import sys
import time
import urllib.request

BOARDS = sys.argv[1:] or ["figma"]
FIELDS = ["board", "id", "company", "title", "department", "location", "firstPublished", "updatedAt",
          "salaryMin", "salaryMax", "currency", "salaryTitle", "url"]


def get_board(board):
    url = f"https://boards-api.greenhouse.io/v1/boards/{board}/jobs?content=true&pay_transparency=true"
    request = urllib.request.Request(url, headers={"User-Agent": "greenhouse-jobs-script"})
    with urllib.request.urlopen(request, timeout=60) as response:
        return json.load(response)["jobs"]


def amount(cents):  # Greenhouse sends amounts in cents
    if cents is None:
        return None
    return cents / 100 if cents % 100 else cents // 100


def salary(job):
    for pay in job.get("pay_input_ranges") or []:
        return amount(pay.get("min_cents")), amount(pay.get("max_cents")), pay.get("currency_type"), pay.get("title")
    return None, None, None, None


with open("greenhouse_jobs.csv", "w", newline="", encoding="utf-8") as file:
    writer = csv.writer(file)
    writer.writerow(FIELDS)
    for board in BOARDS:
        jobs = get_board(board)
        for j in jobs:
            department = (j.get("departments") or [{}])[0].get("name")
            writer.writerow([board, j["id"], j.get("company_name"), j["title"].strip(), department,
                             ((j.get("location") or {}).get("name") or "").strip(), j.get("first_published"),
                             j.get("updated_at"), *salary(j), j.get("absolute_url")])
        print(f"{board}: {len(jobs)} jobs")
        time.sleep(1)  # one request per board, with a pause

Run it with the board tokens after the file name:

$ python3 greenhouse_jobs.py figma airbnb
figma: 141 jobs
airbnb: 188 jobs

What we got on 27 October 2026: a CSV with 329 jobs in 3 seconds, 242 of them with a pay range. One row, as it appears in the file:

figma,5426468004,Figma,"Account Executive, Enterprise",Sales,"San Francisco, CA • New York, NY • United States",2025-01-28T18:57:29-05:00,2026-07-22T05:37:08-04:00,165000,190000,USD,Annual Base Salary Range:,https://boards.greenhouse.io/figma/jobs/5426468004?gh_jid=5426468004

What the script does not do, to stay short: it keeps the first pay range only (a job can have several); it leaves out descriptions and custom fields; it does not filter by title or location; and it stops at the first board that fails (a wrong token gives HTTP Error 404). It also exports everything each time. To get only the jobs that are new since the last run, see our guide how to monitor new jobs at a list of companies.

When the Apify Actor is worth it

The script is enough for a one-off export of a few boards. Our ATS Jobs Scraper on the Apify Store reads the same Greenhouse API in the cloud. It is worth it when you need more than that:

What we got on 27 October 2026, running the Actor's code (version 0.3, the one on the Apify Store) on our machine with this input:

{
    "companies": ["greenhouse:figma", "greenhouse:airbnb"],
    "titleKeywords": ["engineer"],
    "onlyNewJobs": true,
    "stateKey": "greenhouse-guide-test"
}

The first run saved 82 jobs with "engineer" in the title (28 at Figma and 54 at Airbnb; 66 with a pay range) in 3 seconds. The second run, right after, saved 0. The first run of a new history returns the matching jobs up to Max jobs in total, which the form prefills at 500, and up to 100 jobs on Apify's free plan. With Only new or changed jobs on, the jobs left out by a limit come in the next runs, as long as they are still posted. How to schedule it is explained in the monitoring guide.

The Actor charges per job a run saves, plus Apify's small start charge for each run. The current prices are in the Pricing tab of the Actor's page.

Questions and answers

Do I need a Greenhouse account or an API key?
Not to read published jobs. The documentation asks for a Job Board API key only to submit applications through the API, which this guide does not cover.
Is it allowed to read Greenhouse job boards?
Greenhouse describes the API for companies that build their own careers pages, and it needs no login or key. Its documentation says that "Job Board data is publicly available" — a statement about access, not a permission for every use. Keep a gentle pace (one request per board, with a pause), and check that your use of the job texts is allowed where you are.
Can I list every company that uses Greenhouse?
No. The API works one board at a time, and neither the script nor the Actor has a directory of companies. You start from your own list: look for greenhouse.io in the address of a job page or of the Apply button, or for gh_jid in the address of a job on the company's own site, then find the token in the page source.
Why are some pay ranges missing or without a period?
Greenhouse returns pay ranges only where the employer has set them up for the job post. The range has no interval field, so "per year" or "per hour" is known only when the employer writes it in the range title.
What about Lever, Ashby and Workday?
Lever and Ashby have their own guides: how to export jobs and salaries from Lever job sites and how to export jobs and salaries from Ashby job boards. The monitoring guide has a script for Greenhouse, Lever and Ashby together. Workday is covered in how to export job postings from a Workday career site.

API, script and Actor tested by Quicksloth on 27 October 2026 on the public Greenhouse job boards of Figma and Airbnb; job counts change every day. Field descriptions come from Greenhouse's documentation read on 27 October 2026. Written with AI tools and checked by Quicksloth. Quicksloth is an independent developer and is not affiliated with Greenhouse, Apify or the companies named. Greenhouse and Apify are trademarks of their respective owners.