# Greenhouse Board Delta Feed (`f108/greenhouse-board-delta-feed`) Actor

Track public Greenhouse job boards with persistent snapshots, added and updated roles, and removals confirmed across two successful checks. Pay per board check, not per job.

- **URL**: https://apify.com/f108/greenhouse-board-delta-feed.md
- **Developed by:** [Fumiya Hanzawa](https://apify.com/f108) (community)
- **Categories:** Jobs, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $5.00 / 1,000 board checks

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 Board Delta Feed

Monitor known public Greenhouse job boards using the official Job Board GET API. Receive structured
added, updated and removed roles across scheduled runs, with a predictable charge per complete board check.
No browser, proxy, account credentials, paid external API or LLM is required.

### Quick start

```json
{"boards":["airbnb"],"stateKey":"my-hiring-watch"}
```

Supply 1–10 lowercase board tokens from public Greenhouse job-board URLs. This is not company discovery.
The first run returns a baseline with all active jobs in `added`; it does not claim they were newly posted.
Later runs compare job-post ID, title and location. A changed URL is not inferred from arbitrary redirects.
We construct canonical Greenhouse job links and never follow links from the response.

### Output and removal semantics

One Dataset row per successful board: board, status (baseline/changed/unchanged), activeJobs, added,
updated (before/after), removed, pendingRemovalIds and checkedAt. Arrays contain IDs, titles, locations
and canonical links. The summary is in OUTPUT; LAST\_CHARGE records the latest charge confirmation.
Removed means absent in **two consecutive successful complete observations**, not a confirmed hire or
closed requisition. Missing jobs remain pending after the first observation. Reappearance clears pending.
Errors never advance the snapshot or infer removal. Updated compares only title/location/link; descriptions,
salaries, metadata and upstream updated\_at timestamps are outside this MVP's comparison scope.

Up to 2,000 jobs and 4 MB decoded response per board. The source's meta.total must match the list length.
Oversize, partial, malformed, redirected and failed responses fail the run, retain the previous snapshot,
and produce an uncharged error row. Processing stops at the first source error; earlier successful boards
remain billable. A complete empty response is a successful billable observation.

### Pricing

- board-check: **$0.005 per complete successful board check**, regardless of job count within the limits.
- apify-actor-start: **$0.00005 per started GB**, minimum one event. Memory is fixed at 256 MB.
- No Dataset-item event and no separate platform usage surcharge. Post-run storage/export may have plan costs.
- Set Console maximum charge or API maxTotalChargeUsd. $0.00505 covers one board and one start.

Dataset is saved before charging; snapshot is updated only after confirmed charging. There is no charge for
failed source checks, but the start charge remains. A limit prevents further board requests; it is per run,
not per month. SDK charging uses its idempotency mechanism. Storage and charge are not atomic: interruption
can leave a saved uncharged row or a charged row before its snapshot update. A resurrected run is rejected
to avoid repeating charges. A new run is a separate billable observation.

### Scheduling and retention

**Do not run the same stateKey concurrently in one account.** Serialize integrations and schedules; use
different keys for independent monitors. A daily schedule normally suits hiring changes; no schedule is
created automatically. Named `greenhouse-delta-<stateKey>` storage retains accepted compact snapshots and
pending-removal IDs until you delete it. Removing a board from input does not delete its saved snapshot.
Dataset diffs and default stores follow your plan's retention; named stores persist. Manage deletion yourself
and review retention at least every 30 days. No destructive automatic retention job is installed.

To delete: stop schedules and active runs, verify the matching named KVS, delete it in Console Storage;
delete each associated Dataset and default KVS separately, plus obsolete runs/logs and downstream exports.
The next run starts a new baseline. Do not resurrect old runs after deleting their PROCESSING\_STARTED marker.
Use authenticated DELETE /v2/key-value-stores/{id}, /v2/datasets/{id} for verified storage IDs in your automation.
Protect storage with restricted access; Actor visibility is separate from storage visibility.

### Safety, rights and limitations

Only fixed-origin HTTPS requests to boards-api.greenhouse.io are made. Arbitrary URLs, credentials, redirects,
login/CAPTCHA/access-control bypass and application submissions are unsupported. Tokens are board identifiers,
not API secrets. We do not request content=true, applicant fields, candidate data or personal contact metadata.
Only job ID/title/location/canonical link are retained; do not target boards that place personal or confidential
information in these public fields. No job content is sent to an LLM or another enrichment provider.

Users are responsible for source rights, terms, robots policies and reasonable frequency. Public API access
is not a blanket license to republish job data. We do not claim fully automated legal/robots compliance.
Normal use needs no operator approval per board; serious source/security exceptions require human review.
API changes and temporary missing jobs can still affect results. No completeness beyond the validated source
response and no hiring-outcome accuracy is promised. This is not an official Greenhouse product.

[Official source API](https://docs.greenhouse.io/job-board.html)

### API and agents

Use Apify Actor run API with this input schema and retrieve OUTPUT/Dataset via the output schema links.
The same bounded inputs can be used through Apify's Actor MCP integration; no custom MCP server or Standby
process is required. API execution is tested; MCP-client execution is not separately certified.

### Development

Python 3.12, Apify SDK 4.0.2. Run `python -m board_delta` or `apify run` in this directory.
Offline tests: from workspace root, set PYTHONPATH=second\_actor and run pytest second\_actor/tests.

# Actor input Schema

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

1–10 lowercase Greenhouse board tokens, e.g. airbnb. URLs, credentials and private boards are not accepted.

## `stateKey` (type: `string`):

Serialize runs with the same key. Named snapshots persist until you delete them.

## Actor input object example

```json
{
  "boards": [
    "airbnb"
  ],
  "stateKey": "default"
}
```

# Actor output Schema

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

No description

## `summary` (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": [
        "airbnb"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("f108/greenhouse-board-delta-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": ["airbnb"] }

# Run the Actor and wait for it to finish
run = client.actor("f108/greenhouse-board-delta-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": [
    "airbnb"
  ]
}' |
apify call f108/greenhouse-board-delta-feed --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,f108/greenhouse-board-delta-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/6h5r0Y9rtuueGjoV9/builds/JiDi52egt2Iyptqd9/openapi.json
