# Greenhouse Jobs + Expiry History — major tech companies (`hyperbach/greenhouse-jobs-history`) Actor

Hiring at major tech companies — Stripe, Anthropic, Airbnb, GitLab, Cloudflare, Reddit and more — straight from each company's own Greenhouse board. Exact-employer data, not a job-board aggregation, with full role detail, kept as roles open and close. Served at database speed.

- **URL**: https://apify.com/hyperbach/greenhouse-jobs-history.md
- **Developed by:** [Hyperbach](https://apify.com/hyperbach) (community)
- **Categories:** Jobs
- **Stats:** 3 total users, 2 monthly users, 22.5% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$2.50 / 1,000 results

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/platform/actors/running/actors-in-store#pay-per-event

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.
Actors are written with capital "A".

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## Greenhouse Jobs + Expiry History — major tech companies

**The hiring of major tech companies — Stripe, Anthropic, Airbnb, GitLab, Cloudflare, Reddit and more — straight from each company's own Greenhouse board.** Not a job-board aggregation: every posting is tied to the exact employer, kept as roles open and close. Served at database speed.

### Why this feed, not a generic ATS scrape

- **Exact employer, from its own ATS.** Every posting comes from a specific company's own Greenhouse board (`company_slug` is the employer, `url` is its `boards.greenhouse.io` page) — not a name guessed across an aggregator. When it says Stripe, it *is* Stripe.
- **A curated set of major tech companies.** Maintained fresh across the employers people actually track — Stripe, Anthropic, Airbnb, GitLab, Cloudflare, Reddit, Duolingo, Databricks, Brex, Figma, Vercel, Robinhood — so you don't have to hunt down board tokens. The set grows.
- **Kept after they close.** When a role leaves the board it's retained with the date it closed, so you can see how long positions stay open and which roles a company fills fast — history a live scrape structurally cannot produce.
- **Full role detail, clean and typed.** Title, full description, location, department and the direct apply link as structured fields — not raw HTML you have to post-process.
- **Database speed, and unblockable.** You read our maintained archive, not the ATS, so a run answers as a query and is never rate-limited or blocked.

### Who it's for

- **Recruiters & talent researchers** — track exactly what the major tech companies are hiring, in which functions, and how fast roles turn over — a competitive-hiring and sourcing signal tied to the exact employer.
- **Market & investment researchers** — which big tech companies are scaling, in what functions, and when they pause hiring — read straight off the per-company feed and its close dates.
- **Founders & sales teams** — who's hiring what at the companies you sell to — an org-growth signal tied to the exact employer and its own careers page.

### Quick start

**One company's board**

```json
{
  "company": "stripe"
}
```

**Engineering roles at a company**

```json
{
  "company": "anthropic",
  "keyword": "engineer"
}
```

**What has closed**

```json
{
  "company": "airbnb",
  "status": "gone"
}
```

### Output

One record per posting:

| field | meaning |
|---|---|
| `job_id` | Stable unique key for the posting, `<source>:<id>`. Deduplicate across runs and join to your own data on this. |
| `url` | Canonical posting URL. |
| `title` | Job title. |
| `company` | Employer name as the board lists it. |
| `company_slug` | The board's identifier for the employer. |
| `company_logo_url` | Employer logo, when the board provides one. |
| `location_restriction` | Where the posting says the role may be based. |
| `categories` | Category tags the board assigned to the posting. |
| `description` | Full posting description. |
| `posted_at` | When the posting first appeared. |
| `first_seen_at` | When our archive first captured it. |
| `status` | `live` while listed, `gone` once removed. |
| `gone_reason` | Set when the role leaves the board. Greenhouse posts no expiry date, so this is `unknown` — it records that the role closed (filled or pulled), and `status`/the timestamps tell you when. |
| `gone_at` | The date the posting was first observed gone. Null while it is live. Naukri overwrites its expired list nightly, so this is only knowable to whoever was watching that day. |
| `apply_url` | Where to apply for the role. |
| `enriched` | Whether category and logo have been resolved yet — a posting is returned as soon as it is found, enriched or not. |

Example record:

```json
{
  "job_id": "greenhouse_ats:8642781002",
  "url": "https://www.brex.com/careers/8642781002?gh_jid=8642781002",
  "title": "Startups Partnerships Manager",
  "company": "Brex",
  "company_slug": "brex",
  "company_logo_url": "https://www.brex.com/api/proxy-image?url=https%3A%2F%2Fbrand.brex.com%2Ftransform%2F7b10bdf8-ed31-4a40-8429-c9fe54f83aa5%2FHomepage-preview%3Fio%3Dtransform%3Afit%2Cwidth%3A1200",
  "location_restriction": "San Francisco, California, United States",
  "categories": [],
  "description": "&lt;div class=&quot;content-intro&quot;&gt;&lt;p&gt;&lt;strong&gt;Why join us&lt;/strong&gt;&lt;/p&gt;\n&lt;p&gt;Brex is the intelligent finance platform that enables companies to s …(truncated for display)",
  "posted_at": "2026-07-24 18:42:03+00",
  "first_seen_at": "2026-07-26 18:54:07.084012+00",
  "status": "live",
  "gone_reason": null,
  "gone_at": null,
  "apply_url": "https://www.brex.com/careers/8642781002?gh_jid=8642781002",
  "enriched": true
}
```

### Pricing

**$0.0025 per result** — pay only for the postings a run returns, **no start fee**. Above the $0.0015–0.002 generic Greenhouse scrapers because you get a *curated, maintained* set of major tech companies plus the **archive** (roles kept after they close) — neither of which a live board scrape gives you. Below the Ashby archive ($0.003), which also carries salary; Greenhouse's board API exposes none.

### Usage patterns

- **Track one company** — Pass `company` (e.g. `stripe`, `anthropic`, `airbnb`) to get that employer's full current board, then poll to watch it change over time.
- **What closed, and when** — Set `status=gone` to see roles that have left the board, with the date — a company that fills a role in two weeks is a different signal than one that leaves it open for months.
- **Incremental sync** — Leave `postedSince` empty; each run continues from the previous one's cursor — no duplicates, nothing skipped.

### Input configuration

| field | type | default | what it does |
|---|---|---|---|
| `keyword` | `string` |  | Matches job title or category. |
| `company` | `string` |  | Employer name as the board lists it. Partial matches work. |
| `postedSince` | `string` |  | ISO timestamp. Leave empty and the Actor remembers where it stopped, returning only new postings each run. |
| `goneSince` | `string` |  | Only postings observed dead at or after this ISO timestamp. The query this archive exists to answer. |
| `status` | `live` / `gone` / `any` | `"live"` | 'Gone' returns postings that have been removed, with why — the part no live scraper can give you. |
| `location` | `string` |  | Substring match on the posting's location. |
| `remoteOnly` | `boolean` | `false` | Only postings the employer marks as remote. |
| `descriptionSearch` | `string` |  | Substring match inside the job description. |
| `excludeTitle` | `string` |  | Drop postings whose title contains this. |
| `maxItems` | `integer` | `500` | Upper bound on results returned in a single run. |
| `fullRefresh` | `boolean` | `false` | By default each run returns only what appeared since your last one, so a schedule never re-delivers the same page. Tick this to ignore that bookmark and re-pull the full result set for your filters — and it clears the stored cursor, so your next ordinary run starts clean. |
| `enrichedOnly` | `boolean` | `false` | Return only postings whose salary, employment type and description have been parsed. Off by default: an unenriched record still carries title, company, location and dates, and withholding it trades a real answer for a slower better one. |

### FAQ

**How is this different from a generic Greenhouse scraper?**

Generic scrapers take any board token and return whatever is live right now. This is a *maintained, curated* feed of major tech companies, and it's an **archive**: roles are kept after they close (`status=gone`), so you get hiring *history* — which roles turn over fast, when a company stops hiring — that a live scrape can't produce.

**Which companies are covered?**

A curated set of major tech employers — currently Stripe, Anthropic, Airbnb, GitLab, Cloudflare, Reddit, Duolingo, Databricks, Brex, Figma, Vercel and Robinhood — and growing. Filter with `company`.

**Does it include salary?**

No. Greenhouse's board API doesn't expose a compensation band, so this feed doesn't invent one — you get the exact employer, role, location, department, description and apply link, plus the archive. If you need salary, the Ashby hiring archive covers a different set of companies whose boards *do* post comp bands.

**Is the archive live, and what does `gone` mean?**

It's a continuously maintained archive: new roles appear within a day, and closed ones stay with the date they left the board. Greenhouse posts no expiry date, so `gone_reason` is `unknown` — the signal is *that* a role closed and *when*, not filled-vs-expired.

### Integration

#### JavaScript

```javascript
import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: 'YOUR_TOKEN' });
const run = await client.actor('hyperbach/greenhouse-jobs-history').call({"company": "stripe"});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
```

#### Python

```python
from apify_client import ApifyClient
client = ApifyClient('YOUR_TOKEN')
run = client.actor('hyperbach/greenhouse-jobs-history').call(run_input={'company': 'stripe'})
items = client.dataset(run['defaultDatasetId']).list_items().items
```

#### CLI

```bash
apify call hyperbach/greenhouse-jobs-history --input '{"company": "stripe"}'
```

#### REST

```bash
curl -X POST "https://api.apify.com/v2/acts/hyperbach~greenhouse-jobs-history/run-sync-get-dataset-items?token=YOUR_TOKEN" \
  -H 'Content-Type: application/json' -d '{"company": "stripe"}'
```

### Support

support@hyperbach.com

*This page is generated from the Actor's schemas and a live sample — it cannot describe a field the Actor does not have.*

# Actor input Schema

## `keyword` (type: `string`):

Matches job title or category.

## `company` (type: `string`):

Employer name as the board lists it. Partial matches work.

## `postedSince` (type: `string`):

ISO timestamp. Leave empty and the Actor remembers where it stopped, returning only new postings each run.

## `goneSince` (type: `string`):

Only postings observed dead at or after this ISO timestamp. The query this archive exists to answer.

## `status` (type: `string`):

'Gone' returns postings that have been removed, with why — the part no live scraper can give you.

## `location` (type: `string`):

Substring match on the posting's location.

## `remoteOnly` (type: `boolean`):

Only postings the employer marks as remote.

## `descriptionSearch` (type: `string`):

Substring match inside the job description.

## `excludeTitle` (type: `string`):

Drop postings whose title contains this.

## `maxItems` (type: `integer`):

Upper bound on results returned in a single run.

## `fullRefresh` (type: `boolean`):

By default each run returns only what appeared since your last one, so a schedule never re-delivers the same page. Tick this to ignore that bookmark and re-pull the full result set for your filters — and it clears the stored cursor, so your next ordinary run starts clean.

## `enrichedOnly` (type: `boolean`):

Return only postings whose salary, employment type and description have been parsed. Off by default: an unenriched record still carries title, company, location and dates, and withholding it trades a real answer for a slower better one.

## Actor input object example

```json
{
  "status": "live",
  "remoteOnly": false,
  "maxItems": 500,
  "fullRefresh": false,
  "enrichedOnly": false
}
```

# Actor output Schema

## `results` (type: `string`):

All scraped records in the default dataset. One record per posting:

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {};

// Run the Actor and wait for it to finish
const run = await client.actor("hyperbach/greenhouse-jobs-history").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {}

# Run the Actor and wait for it to finish
run = client.actor("hyperbach/greenhouse-jobs-history").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print("💾 Check your data here: https://console.apify.com/storage/datasets/" + run["defaultDatasetId"])
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{}' |
apify call hyperbach/greenhouse-jobs-history --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=hyperbach/greenhouse-jobs-history",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/GrdxlPJK3IsJ8bW68/builds/FOLufimnmErfGFqY1/openapi.json
