Practical guide

How to Export All Jobs from a Greenhouse, Lever or Ashby Job Board (Free Public APIs)

Last reviewed: October 22, 2026

Find the hosted board, read its public jobs endpoint and convert the response to CSV. Public board GET requests differ from authenticated recruiting APIs used to manage candidates. These examples export listings without submitting applications.

Find the board token or slug

Follow a job link from the company careers page. On a hosted board, the path or subdomain identifies the board. For a custom page, inspect linked hosted jobs or the browser Network panel for its JSON request. Confirm branding and destinations; a plausible slug alone is not identity evidence.

Hosted boardIdentifier
job-boards.greenhouse.io/stripeGreenhouse token: stripe
jobs.lever.co/spotifyLever site: spotify
jobs.ashbyhq.com/rampAshby board: ramp
apply.workable.com/blueground/Workable account: blueground
fastned.recruitee.com/Recruitee subdomain: fastned

These examples were checked October 22, 2026. They are not endorsements or permanent fixtures. Companies can migrate between ATS providers.

Exact public job board API endpoints

PlatformGET endpointResponse and pagination
Greenhousehttps://boards-api.greenhouse.io/v1/boards/{token}/jobs?content=trueObject with jobs array; no paging parameter documented for this route.
Leverhttps://api.lever.co/v0/postings/{company}?mode=jsonArray; use limit and skip. EU host: api.eu.lever.co.
Ashbyhttps://api.ashbyhq.com/posting-api/job-board/{name}?includeCompensation=trueObject with jobs array; no pagination documented for this public route.
Workablehttps://apply.workable.com/api/v1/widget/accounts/{slug}Object with jobs array. Public widget, not authenticated SPI API.
Recruiteehttps://{slug}.recruitee.com/api/offers/Object with offers array; reference documents department/tag filters, not paging.

All five example endpoints returned HTTP 200 and valid arrays in live curl checks. Workable documents its widget, but a stable public contract for the exact widget route was not established. Validate its schema each run. Sources: Greenhouse: Job Board API, Lever: official Postings API documentation, Ashby: public Job Postings API, Workable: careers page options, Workable: live widget response checked October 22, 2026 and Recruitee: public careers offers endpoint.

Recruitee notice: official docs announce a Careers Site API token deadline of February 10, 2027, after which unauthenticated calls return 401. Do not promise ongoing keyless access. The page excludes XML feeds and the jobs widget from that scope. Recruitee: February 2027 authentication deadline.

Greenhouse and Ashby: curl plus jq to CSV

Use curl and jq from your normal system tools. Quote URLs so ampersands do not become shell operators. Save and validate JSON before conversion. The examples select practical columns while retaining the original response for secondary locations, descriptions and compensation.

curl --fail --silent --show-error --max-time 30 \
  'https://boards-api.greenhouse.io/v1/boards/stripe/jobs?content=true' > greenhouse.json
jq -e '.jobs | type == "array"' greenhouse.json
jq -r '(["id","title","location","department","url"]),
  (.jobs[] | [.id,.title,.location.name,
    ([.departments[]?.name] | join("; ")),.absolute_url]) | @csv' \
  greenhouse.json > greenhouse.csv

curl --fail --silent --show-error --max-time 30 \
  'https://api.ashbyhq.com/posting-api/job-board/ramp?includeCompensation=true' > ashby.json
jq -e '.jobs | type == "array"' ashby.json
jq -r '(["id","title","location","department","apply_url"]),
  (.jobs[] | [.id,.title,.location,.department,.applyUrl]) | @csv' \
  ashby.json > ashby.csv

Run each block in a shell that stops on errors, for example a Bash script with set -euo pipefail. Ashby compensation still depends on supplied data. Do not invent missing salary. The jq manual documents CSV quoting.

Lever pagination beyond the first page

Save as export_lever.sh and run bash export_lever.sh spotify. This Bash example uses limit/skip and spaces requests. It continues until an empty page rather than assuming the server honored the requested page size.

#!/usr/bin/env bash
set -euo pipefail
company="$1"  # Usage: bash export_lever.sh spotify
api='https://api.lever.co'  # EU boards: https://api.eu.lever.co
skip=0
limit=100
printf '%s\n' 'id,title,location,department,apply_url' > lever.csv
while :; do
  page=$(curl --fail --silent --show-error --max-time 30 \
    "$api/v0/postings/$company?mode=json&limit=$limit&skip=$skip")
  count=$(jq -er 'if type=="array" then length else error("Expected array") end' <<<"$page")
  [ "$count" -gt 0 ] || break
  jq -r '.[] | [.id,.text,.categories.location,.categories.department,.applyUrl] | @csv' \
    <<<"$page" >> lever.csv
  skip=$((skip + count))
  sleep 1
done

Use the EU API host for a board on jobs.eu.lever.co. This one-off script stops on HTTP errors; discard partial CSV output. For recurring collection, add finite retries, backoff, a request cap and repeated-page detection. Never retry authorization failures with credentials you do not have.

Workable and Recruitee exports

curl --fail --silent --show-error --max-time 30 \
  'https://apply.workable.com/api/v1/widget/accounts/blueground' > workable.json
jq -e '.jobs | type == "array"' workable.json
jq -r '(["id","title","city","apply_url"]),
  (.jobs[] | [.shortcode,.title,.city,.application_url]) | @csv' \
  workable.json > workable.csv

curl --fail --silent --show-error --max-time 30 \
  'https://fastned.recruitee.com/api/offers/' > recruitee.json
jq -e '.offers | type == "array"' recruitee.json
jq -r '(["id","title","location","apply_url"]),
  (.offers[] | [.id,.title,.location,.careers_apply_url]) | @csv' \
  recruitee.json > recruitee.csv

The Workable widget can expose summaries without descriptions or salaries. Recruitee may supply multiple locations and translations. Select required fields rather than redistributing entire payloads, which can contain contact and application-related fields.

Completeness, limits and the easy option

Compare counts with the board at collection time, recognizing that postings can change during pagination. Preserve IDs as strings and deduplicate by platform, board and native ID. A changed title is not a new ID. An empty valid array differs from a failed fetch.

Read robots.txt and applicable terms. Use a truthful client identifier, low request volume and backoff for temporary errors. Do not bypass access blocks or disabled endpoints. Import untrusted CSV fields as text in spreadsheets to avoid formula interpretation.

ATS Jobs Scraper accepts platform prefixes or hosted URLs and normalizes titles, locations, departments, apply links and salary when exposed. Missing values remain null. Explicit platforms avoid ambiguous auto-detection.

{
  "companies": ["greenhouse:stripe", "lever:spotify", "ashby:ramp"],
  "includeDescription": true,
  "maxJobsPerCompany": 0,
  "maxResults": 2000,
  "requestDelayMs": 1000
}

Increase caps for a larger inventory and check RUN_SUMMARY. Filters and caps can omit jobs. “All jobs” requires successful complete fetches and sufficient output limits. For repeat runs, follow the new-posting monitoring guide.

Frequently asked questions

Do these exports need an ATS API key?

The tested public GET routes worked without a key on October 22, 2026. Recruitee announces a Careers Site API token deadline for February 10, 2027. Management APIs are separate.

Why is the board token hard to find?

A company can use a custom page or a different ATS. Inspect a hosted job link or JSON request and verify ownership before trusting a guessed slug.

Does one Lever request guarantee all jobs?

No. Use limit and skip, continue paging and verify a complete export before replacing a monitoring baseline.

Why are salary or description fields empty?

The public source may not expose them or the employer may not supply them. Preserve unknowns rather than inferring missing data.

Sources

Primary documentation and official authorities reviewed for this guide. Live responses are observations on the review date; source policies and laws can change.

Tool inputs, outputs and limitations: ATS Jobs Scraper documentation.