# Greenhouse Job Change Feed (`saahir-job-data/greenhouse-job-change-feed`) Actor

Greenhouse job scraper with clean text, stable IDs, source links and change detection. Compare a supplied snapshot to return new or updated postings. Bounded runs with completeness reports and API-ready output for job boards, hiring research and AI agents.

- **URL**: https://apify.com/saahir-job-data/greenhouse-job-change-feed.md
- **Developed by:** [Saahir Sultan](https://apify.com/saahir-job-data) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.00 / 1,000 job records

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/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
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.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## 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.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## Greenhouse Job Change Feed

Turn public Greenhouse job boards into structured records with clean descriptions, stable IDs, source links and content fingerprints. Use the output for job-board feeds, hiring research, or automated agents that need to track postings from specified companies.

### What it returns

Each delivered record contains one job observation. Missing source fields remain null; the Actor does not invent salaries or company information.

| Fields | Meaning |
| --- | --- |
| `id`, `provider`, `board`, `sourceJobId` | Stable record identity and source board |
| `title`, `company`, `location`, `departments` | Source-supplied job details |
| `description` | Job description converted to plain text |
| `url`, `source` | Original posting and public source API |
| `sourcePublishedAt`, `sourceUpdatedAt` | Available source timestamps |
| `language`, `requisitionId` | Available source metadata |
| `observedAt` | Time this run observed the posting |
| `fingerprint` | SHA-256 fingerprint of the normalized content |
| `change` | `new`, `changed`, or `unchanged` relative to your snapshot |

### Start with a company board

Supply the board token from a public Greenhouse board, such as `stripe`.

```json
{
  "boards": ["stripe"],
  "maxResults": 1000,
  "maxRequests": 1,
  "maxSeconds": 90,
  "changesOnly": false
}
```

The default dataset contains job records. The default key-value store contains `REPORT` with completeness, limits and errors, and `SNAPSHOT` with fingerprints for your next comparison. Read REPORT before treating a run as a full inventory.

### Return only changed jobs

Pass the prior run's SNAPSHOT JSON as `previousSnapshot` and enable `changesOnly`. The Actor suppresses unchanged records. Without a baseline, returned jobs are new to this run. Observation time and source update time alone do not trigger a content change.

Snapshots are caller-managed; this Actor does not retrieve them from earlier runs automatically. There is no shared customer snapshot. Jobs absent from a later response are retained in the snapshot and are never declared closed. A partial run updates fingerprints only for delivered records, so comparisons do not imply a complete publishing history.

### Input and run limits

- `boards`: 1–20 Greenhouse tokens, containing letters, numbers, underscores or hyphens.
- `maxResults`: 1–10,000 delivered records; default 1,000.
- `maxRequests`: 1–20 source requests; default 20. One request per board, without automatic retries.
- `maxSeconds`: 1–120 seconds of processing; default 90. A pending socket read can take up to 12 additional seconds.
- `previousSnapshot`: up to 20,000 fingerprint entries; optional.
- `changesOnly`: false by default.

Cloud defaults are 512 MB and a 180-second timeout. Response and transfer limits are 16 MB per response and 64 MB per run. Invalid, duplicate or inconsistent feeds fail that board before its records are delivered. Limits can produce partial output; REPORT explains the stop reason. Forced restarts are not guaranteed to deliver records exactly once.

### Pricing

**$2 per 1,000 delivered job records**, plus **$0.00005 per Actor start** at the supported memory allocation. Platform usage is included in this event pricing. A 1,000-record run costs $2.00005 at these prices.

Unchanged jobs suppressed by `changesOnly` and source errors have no record charge. The start event still applies when a run returns no records. Each observation delivered on a later run is a new billable result, including repeated jobs when `changesOnly` is off.

Set Maximum cost per run to control your budget. The minimum selectable budget is $0.003; the configured default is $2.01. The Actor limits delivered records to the available event budget. Check the Pricing tab for the active rates before running.

### Scope

Greenhouse public boards only. The Actor does not submit applications, collect applicant records, enrich personal contact details, infer job closures, or bypass blocked pages. Use source data in accordance with applicable terms and your rights to use it. No affiliation with Greenhouse or listed employers is claimed.

# Actor input Schema

## `boards` (type: `array`):

1 to 20 board tokens, such as stripe. Only letters, digits, underscores and hyphens.

## `maxResults` (type: `integer`):

A paid record is one job observation. Errors and skipped unchanged jobs are not dataset items.

## `maxRequests` (type: `integer`):

One request per board. No automatic retries.

## `maxSeconds` (type: `integer`):

Stops new work at this many seconds. An in-flight network read can take up to 12 additional seconds.

## `changesOnly` (type: `boolean`):

Requires a previousSnapshot to suppress unchanged records. No jobs are inferred to be closed.

## `previousSnapshot` (type: `object`):

Optional SNAPSHOT JSON from an earlier run. Keys are job IDs; values are SHA-256 fingerprints. At most 20000 entries. No shared state between customers.

## Actor input object example

```json
{
  "boards": [
    "stripe"
  ],
  "maxResults": 1000,
  "maxRequests": 20,
  "maxSeconds": 90,
  "changesOnly": false,
  "previousSnapshot": {}
}
```

# Actor output Schema

## `jobs` (type: `string`):

No description

## `report` (type: `string`):

No description

## `snapshot` (type: `string`):

No description

# 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 = {
    "boards": [
        "stripe"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("saahir-job-data/greenhouse-job-change-feed").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 = { "boards": ["stripe"] }

# Run the Actor and wait for it to finish
run = client.actor("saahir-job-data/greenhouse-job-change-feed").call(run_input=run_input)

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

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

```

## CLI example

```bash
echo '{
  "boards": [
    "stripe"
  ]
}' |
apify call saahir-job-data/greenhouse-job-change-feed --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,saahir-job-data/greenhouse-job-change-feed"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

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