praxyjobs

FOR Developers building on job data

How to Get Job Postings from Greenhouse (API Guide)

The greenhouse jobs api is free and public. Learn the boards endpoint, the fields you get, how to find board tokens, and the hard parts of doing it at scale.

Praxy Jobs··7 min read

THE FINDING

Yes - the greenhouse jobs api is free and public. GET https://boards-api.greenhouse.io/v1/boards/{board_token}/jobs?content=true returns every open posting with title, departments, offices, location, and full description in one call. The catch is scale: discovering board tokens, deduping, and detecting removals is the real work.

Evidence: · Snapshot:

Yes - the greenhouse jobs api is free and public

The greenhouse jobs api is the read-only Job Board API that every company on Greenhouse exposes automatically - no key, no OAuth, no scraping. If a company hosts its careers page on Greenhouse, you can pull its live openings with a single HTTPS GET.

Three things make it developer-friendly:

The catch isn't the endpoint. It's everything around it: finding which companies are on Greenhouse, knowing when a job disappears, deduping the same role across boards, and recording where each field came from. We'll cover both the easy path and the hard one.

  • No auth. The board endpoints are public. (This is separate from Greenhouse's *Harvest API*, which needs a key and is for the employer's own ATS data.)
  • Structured JSON. Titles, departments, offices, locations, and the full job description come back as JSON - not HTML you have to parse out of a page.
  • One call for everything. Add ?content=true and the list response includes each job's full description inline, so you avoid a second request per job.

The endpoint, the parameters, and the fields you get

The core endpoint is:

Here's a runnable example (swap {board_token} for a real one - see the next section):

Each job object gives you:

Two gotchas worth knowing up front:

Companion endpoints exist too: /jobs/{id} for a single posting, and /departments and /offices for the board's taxonomy tree. There's no documented hard rate limit on the public board API, but that isn't an invitation to hammer it - cache responses and poll on a schedule.

  • content is HTML-entity-escaped. You'll get &lt;p&gt; rather than <p>. Unescape it before you render or index it, then strip or sanitize the HTML.
  • Location is a string, not structured geo. "Remote", "London, UK", and "SF / NYC" all arrive as free text. Mapping that to country/city/remote-flag is on you.
Fields returned by the Greenhouse Job Board API
FieldWhat it is
idGreenhouse's numeric job id (stable per posting)
internal_job_idThe requisition id backing the posting
titleRole title as shown on the careers page
location.nameFree-text location string (e.g. "Remote - US")
departments[]Team taxonomy, each with id and name
offices[]Office objects with a name and a location string
contentFull description as an HTML-encoded string (present with content=true)
absolute_urlThe public apply/detail URL
updated_at / first_publishedTimestamps for freshness
https://boards-api.greenhouse.io/v1/boards/{board_token}/jobs?content=true

# Every open job for a board, with full descriptions, in one call
curl -s "https://boards-api.greenhouse.io/v1/boards/{board_token}/jobs?content=true" \
  | jq '.jobs[] | {
      id,
      title,
      location: .location.name,
      updated_at,
      departments: [.departments[].name],
      offices: [.offices[].name],
      url: .absolute_url
    }'

How to find a company's board token

The {board_token} is the company's Greenhouse identifier - usually a lowercased, punctuation-stripped version of the company name (acme, figma, discord). You need the exact token; guessing is unreliable. Three dependable ways to get it:

1. From the careers URL. If a company's jobs live at boards.greenhouse.io/acme or job-boards.greenhouse.io/acme, the token is acme. 2. From the embed script. Companies that iframe Greenhouse into their own site include a script like boards.greenhouse.io/embed/job_board/js?for=acme. The for= value is the token. 3. From the network tab. Load the careers page, watch requests, and you'll see the boards-api.greenhouse.io/v1/boards/{token}/... call the page makes.

The problem: there is no public directory of every Greenhouse board token. Greenhouse doesn't publish "here are all our customers." So if your goal is *"all Greenhouse jobs,"* not *"this one company's jobs,"* token discovery becomes the entire project - and it never stops, because companies sign up, churn, and rename.

The hard parts at scale (why this stops being a one-liner)

Pulling one board is a curl command. Building a reliable, complete, fresh Greenhouse feed is a data pipeline. Here's what you actually have to solve:

Discovery. With no master list of board tokens, you're crawling careers pages, mining embed scripts, and maintaining a company-to-token map for tens of thousands of employers. Miss a token and you silently miss every one of that company's jobs.

Removal detection. The board API only shows *currently open* roles. A job that's filled or pulled just vanishes from the response - there's no "closed" event and no tombstone. To know a posting is gone (and when), you have to diff every board against your last snapshot on a schedule. Skip a poll and your "live" feed quietly rots.

Dedup. The same role shows up on the Greenhouse board, on aggregators, and sometimes across two of a company's own boards. Without a stable dedup key (company + normalized title + location + a content fingerprint), you double-count and your numbers drift.

Normalization. Free-text locations, HTML-encoded descriptions, and per-company department names all have to map to a consistent schema before the data is queryable. Every company names things differently.

Provenance. Six months later, when a field looks wrong, you'll want to know: which endpoint did this come from, when was it fetched, and was the description from Greenhouse or a downstream board? If you didn't record per-field provenance at ingest, you can't answer that - and you can't trust the field.

One honest caveat that survives all of this: a Greenhouse posting is a *posting*, not a hire. It tells you a company is advertising a role. It does not tell you the role was filled, how many people were hired, or the real salary. Don't let a clean API lull you into treating openings as outcomes.

How Praxy delivers Greenhouse jobs with provenance

Praxy Jobs runs the pipeline above so you don't have to. Greenhouse is one of 50+ ATS and board sources behind a single API - and you can isolate it with one filter.

What you get on top of the raw board data:

And we hold the same honesty bar: postings are postings, not hires. We won't dress an advertised opening up as a confirmed outcome, or invent a salary the employer never published.

If you only need one company's jobs, the public Greenhouse endpoint is genuinely all you need - use it. If you need *Greenhouse across the market* - fresh, deduped, and traceable - that's what source=greenhouse is for.

  • Per-field provenance. Every field carries where it came from and when it was fetched - the answer to "is this still true?" lives in the record.
  • Freshness with removal detection. We diff boards on a schedule, so a job that disappears from Greenhouse is marked inactive in the feed instead of lingering.
  • Dedup across sources. The same role from Greenhouse, an aggregator, and a company board collapses to one canonical posting.
  • Embeddings + taxonomy. Every posting is embedded and mapped to a normalized role/skill taxonomy, so semantic search and clean filtering work out of the box.
  • Concurrency-safe cursors. /v1/feed/active streams the corpus with cursors that return a 409 if the feed shifted under you - you never silently skip or double-read pages.
  • Keyless MCP + exports. Query it from an MCP client, or pull NDJSON/Parquet for bulk loads.
curl -s https://api.praxyjobs.com/v1/jobs/search \
  -H "X-API-Key: $PRAXY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"source": "greenhouse", "query": "backend engineer", "limit": 50}'

FREQUENTLY ASKED QUESTIONS

Questions teams ask

Is the Greenhouse jobs API free?+

Yes. The public Job Board API (`boards-api.greenhouse.io`) needs no key or auth and is free to call. It's separate from the authenticated Harvest API. Be polite - cache responses and poll on a schedule rather than hammering it.

Do I need an API key for Greenhouse job postings?+

Not for the public board API - reading a company's open jobs needs no key. You only need credentials for Greenhouse's Harvest API, which is for an employer managing its own ATS data, not for reading public postings.

How do I get the full job description from Greenhouse?+

Add `?content=true` to the jobs endpoint. The `content` field comes back HTML-entity-encoded, so unescape it (e.g. `&lt;` becomes `<`) and sanitize the HTML before rendering or indexing it.

How do I know when a Greenhouse job is closed or removed?+

The board API only returns currently open roles; closed ones simply disappear with no event or tombstone. To detect removals you must snapshot each board on a schedule and diff against the previous pull. Praxy does this and marks vanished jobs inactive.

SOURCES & METHOD

Check the evidence

Related field notes