# ATS Job Link Checker — Greenhouse, Lever & Ashby (`iwins/ats-job-link-checker`) Actor

Check existing job links against live employer feeds. Flag listed, absent and unlisted job IDs with source evidence. Failed or incomplete checks stay unknown. Supports Greenhouse, Lever global/EU and Ashby; no login, AI API or applications.

- **URL**: https://apify.com/iwins/ats-job-link-checker.md
- **Developed by:** [Ahmed Firas](https://apify.com/iwins) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$2.00 / 1,000 job 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

## ATS Job Link Checker

Keep an existing job list fresh. Paste hosted job links from Greenhouse, Lever or Ashby and check whether each exact ID still appears in its employer's public feed. Get a compact report for job-board maintenance, saved-job cleanup or recruiting data quality.

A webpage returning HTTP 200 does not prove a role is still listed. This tool reads the providers' documented public job feeds, follows Lever pagination and keeps incomplete checks **unknown**. It does not search for jobs, determine whether an employer is genuinely hiring, submit applications or decide anything about candidates.

### Start in one minute

1. Paste **1–100 job URLs** from up to **20 employer boards**.
2. Start the run. The examples are public demonstration links, not customers. The Lever example is a demo board.
3. Export **Resolved job checks** to JSON, CSV or Excel using Apify's controls.
4. Open **Full report including unknowns** to see all checked links and provider errors. Unknowns are not included in the billed dataset.

Supported forms:

| Provider | Hosted URL form |
| --- | --- |
| Greenhouse | `https://job-boards.greenhouse.io/company/jobs/12345` or `https://boards.greenhouse.io/company/jobs/12345` |
| Lever global | `https://jobs.lever.co/company/job-uuid` |
| Lever EU | `https://jobs.eu.lever.co/company/job-uuid` |
| Ashby | `https://jobs.ashbyhq.com/company/job-uuid` |

Use a full real job ID. Tracking queries and fragments are removed. Lever/Ashby `/apply` and `/application` suffixes are normalized to the job URL. Repeated jobs are checked once per run. Custom company career domains, board homepages, Greenhouse embeds, LinkedIn, Indeed, Workday and shortened URLs are not supported. The tool never follows arbitrary redirects.

### Understand the result

| Status | Evidence | Appropriate next step |
| --- | --- | --- |
| `listed` | Exact ID found in the current public feed. | Retain as currently listed. This is not proof that applications work or that hiring is genuine. |
| `not_listed` | Exact ID absent from a completely read feed. | Review the source before archiving. A typo, changed ID, migration or never-existing ID can produce this result. |
| `unlisted` | Ashby returned the ID with `isListed=false`. | Review separately. Unlisted does not mean filled or closed. Title/location are omitted. |
| `unknown` | Feed failed, changed shape, exceeded limits or could not be completed, and ID was not found. | Keep the previous state and retry later. Do not delete a job based on this result. |

Every record includes the normalized input URL, provider, employer board token, job ID, observation time, source API URLs, completeness flag and reason. Published title/location appear only for listed jobs. An ID found before a later pagination failure remains `listed`, with `completeBoard=false` and an error code. Absence is never inferred from a partial feed.

`REPORT` in default key-value storage contains all attempted checks, including unknowns and budget counts. `CHECK-001`, etc. contain evidence saved before dataset writes. If a run is interrupted, inspect these individual records and the dataset: the final REPORT might not have been written.

### Pricing

**USD 0.002 per resolved job check** — **$2 per 1,000**, including platform usage. One `listed`, `not_listed` or `unlisted` dataset row is one charged check. `unknown` results have no result charge and live in REPORT. There is no startup event, AI API fee, required proxy or subscription for this Actor.

Examples: 20 resolved links cost $0.04; 100 cost $0.20. Set maximum run cost to at least $0.002. A $0.01 cap permits five resolved results; remaining links are unattempted once this cap is reached. Consult Apify's current Pricing tab before running. New runs recheck and may charge again. This is not pay-once-per-job pricing.

No dataset POST is retried after an uncertain response. Runs with existing dataset rows refuse resurrection to prevent duplicate charges. Inspect saved evidence before initiating another run.

### Coverage and limits

- Reads only documented public GET APIs; no ATS account, candidate data, API keys, applications, browser or AI model.
- Snapshots are cached only within a run. Repeated checks across runs can be scheduled with Apify Tasks, but this Actor does not retain previous status, send alerts or automatically remove entries from your system.
- At most 20 Lever pages of 100 jobs per board (2,000 records). A missing ID on a capped or failed board is unknown. Greenhouse's returned count must match its declared total. Ashby public API version 1 and valid listed states are required.
- Maximum decoded response size 8 MiB, request deadline 15 seconds, at least one second between provider-host requests. One bounded retry for selected transient network errors and HTTP 429/502/503/504. Retry-After longer than ten seconds ends the check.
- Job-board data can change during pagination. Results are observations, not guaranteed current hiring outcomes or proof a vacancy was filled. The input board token is not a verified legal company name.
- Provider outages, blocking or schema changes remain possible. No guarantee of perpetual access or support for every company's ATS configuration.

### Sources and support

The implementation uses the [Greenhouse Job Board API](https://docs.greenhouse.io/job-board.html), [Lever Postings API](https://github.com/lever/postings-api) and [Ashby Public Job Posting API](https://developers.ashbyhq.com/docs/public-job-posting-api). It is independent and is not endorsed by these providers.

[Google's job-posting guidance](https://developers.google.com/search/docs/appearance/structured-data/job-posting#remove-a-job-posting) explains why publishers should maintain expired listings. This Actor does not change your website, submit indexing requests or guarantee Google eligibility.

For support, open an issue with the error code and a public or fictional example. Do not post confidential lists, credentials or candidate details.

# Actor input Schema

## `jobUrls` (type: `array`):

1–100 existing HTTPS job links from up to 20 boards. Greenhouse, Lever global/EU and Ashby hosted URLs only. Trackers are removed and duplicates checked once. Custom career URLs and board homepages are unsupported.

## Actor input object example

```json
{
  "jobUrls": [
    {
      "url": "https://job-boards.greenhouse.io/stripe/jobs/8172508"
    },
    {
      "url": "https://jobs.lever.co/leverdemo/681fbc53-1e34-4a46-8677-3a78118674eb"
    },
    {
      "url": "https://jobs.ashbyhq.com/ashby/7458d4e9-da2e-47bd-98cb-adfda43d42b2"
    }
  ]
}
```

# Actor output Schema

## `checks` (type: `string`):

No description

## `report` (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 = {
    "jobUrls": [
        {
            "url": "https://job-boards.greenhouse.io/stripe/jobs/8172508"
        },
        {
            "url": "https://jobs.lever.co/leverdemo/681fbc53-1e34-4a46-8677-3a78118674eb"
        },
        {
            "url": "https://jobs.ashbyhq.com/ashby/7458d4e9-da2e-47bd-98cb-adfda43d42b2"
        }
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("iwins/ats-job-link-checker").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 = { "jobUrls": [
        { "url": "https://job-boards.greenhouse.io/stripe/jobs/8172508" },
        { "url": "https://jobs.lever.co/leverdemo/681fbc53-1e34-4a46-8677-3a78118674eb" },
        { "url": "https://jobs.ashbyhq.com/ashby/7458d4e9-da2e-47bd-98cb-adfda43d42b2" },
    ] }

# Run the Actor and wait for it to finish
run = client.actor("iwins/ats-job-link-checker").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 '{
  "jobUrls": [
    {
      "url": "https://job-boards.greenhouse.io/stripe/jobs/8172508"
    },
    {
      "url": "https://jobs.lever.co/leverdemo/681fbc53-1e34-4a46-8677-3a78118674eb"
    },
    {
      "url": "https://jobs.ashbyhq.com/ashby/7458d4e9-da2e-47bd-98cb-adfda43d42b2"
    }
  ]
}' |
apify call iwins/ats-job-link-checker --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,iwins/ats-job-link-checker"
        }
    }
}
```

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/NYKtql9acVe7P5m56/builds/fHsTqbCbzIGYhhOzp/openapi.json
