ATS Jobs Scraper API - Greenhouse, Workday, Lever & Ashby avatar

ATS Jobs Scraper API - Greenhouse, Workday, Lever & Ashby

Pricing

from $1.60 / 1,000 job or change records

Go to Apify Store
ATS Jobs Scraper API - Greenhouse, Workday, Lever & Ashby

ATS Jobs Scraper API - Greenhouse, Workday, Lever & Ashby

ATS job scraper & jobs API for Greenhouse, Workday, Lever, Ashby, Workable, Personio, Recruitee & Teamtailor career pages. Scrape normalized job postings with apply URLs, or a change feed of new, updated & closed jobs. No false closures when a source fails.

Pricing

from $1.60 / 1,000 job or change records

Rating

0.0

(0)

Developer

Kamer Ozkan

Kamer Ozkan

Maintained by Community

Actor stats

0

Bookmarked

3

Total users

2

Monthly active users

2 hours ago

Last modified

Categories

Share

Monitor company hiring changes across eight ATS platforms - directly from career pages, with reliable closed-job events and no false closures when a source fails.

ATS Job Change Feed is a source-direct ATS job scraper API, career page monitor, and hiring-signal feed for Greenhouse, Workday, Lever, Ashby, Workable, Personio, Recruitee, and Teamtailor. Give it company websites or ATS board URLs and receive one normalized schema with stable job IDs plus deterministic CREATED, UPDATED, and CLOSED events.

Use it to track competitor hiring, trigger B2B sales workflows, build job alerts, or maintain a reliable recruiting-analytics feed. In scheduled changes mode, unchanged jobs produce no result records, so frequent monitoring does not repeatedly bill the same snapshot.

Unofficial integration. This Actor is independently developed and is not affiliated with, sponsored by, or endorsed by Greenhouse, Lever, Ashby, Workable, Recruitee, Personio, Teamtailor, or Workday. Product names are used only to identify compatible public career-board formats. It reads public company job postings only - never candidates, applications, resumes, or private ATS data.

Why this ATS job scraper is different

Most job scrapers return a fresh snapshot and leave change tracking, deduplication, and failure handling to you. This Actor is designed as an operational job change feed.

Typical snapshot scraperATS Job Change Feed
Returns every open job againEmits only real changes in changes mode
Downstream system must infer closuresEmits explicit CLOSED events
Empty response can look like mass closureFailed or malformed sources retain prior state
One ATS-specific schemaOne schema across eight ATS formats
Requires known ATS URLsCan discover boards from company websites
Generic locations and textDACH locations, KldB, languages, skills, and salary signals
Duplicate suppression is opaqueCross-ATS duplicates remain visible and auditable

What can this career page monitor do?

Job postings often appear on the employer's own ATS career board before they reach job aggregators. The Actor connects to those source endpoints and:

  • reads public career-board JSON, XML, and RSS without a browser, login, or candidate account;
  • discovers supported ATS boards from public company and careers pages;
  • normalizes eight ATS formats into one stable schema;
  • assigns deterministic IDs based on the ATS board and source job ID;
  • assigns stable company identities and marks likely cross-ATS duplicates;
  • records firstSeenAt, lastSeenAt, published, and updated timestamps;
  • detects new, edited, and closed jobs across scheduled runs;
  • merges multi-location variants instead of returning duplicates;
  • recognizes DACH job types such as WORKING_STUDENT, APPRENTICESHIP, and MINIJOB;
  • enriches DACH locations, KldB groups, language requirements, skills, and salary ranges;
  • keeps a failed board's previous snapshot, preventing false mass closures;
  • can bootstrap a versioned 10,000-board candidate catalog and process it in deterministic lifecycle-managed chunks.

Start monitoring jobs in 30 seconds

Paste one or more company career pages. The Actor discovers supported ATS boards and creates the first baseline:

{
"boards": [],
"companyUrls": [
"https://linear.app/careers"
],
"outputMode": "changes",
"stateKey": "competitor-hiring-watchlist",
"emitInitialSnapshotChanges": true
}

Save the input as a task and schedule it every ten minutes. Later runs return only new, updated, and closed jobs. If a board fails, its last successful snapshot is preserved and no synthetic closures are emitted.

Supported career boards

ATSAccepted board URL
Greenhousehttps://job-boards.greenhouse.io/{company}
Greenhouse legacyhttps://boards.greenhouse.io/{company}
Leverhttps://jobs.lever.co/{company}
Lever EUhttps://jobs.eu.lever.co/{company}
Ashbyhttps://jobs.ashbyhq.com/{company}
Workablehttps://apply.workable.com/{company}
Recruiteehttps://{company}.recruitee.com
Personiohttps://{company}.jobs.personio.de
Teamtailorhttps://{company}.teamtailor.com
Workdayhttps://{tenant}.wd{cluster}.myworkdayjobs.com/{career-site}

You can also provide an explicit ats and slug. A single Workable job URL does not contain the company's account slug and cannot be used as a board URL. Workday requires a board URL because both its tenant and career-site name are needed.

Teamtailor is read from its public jobs RSS feed and requires no API token. Workday search results are fetched with consistency-checked pagination. When includeDescriptions is enabled, the Actor also requests every Workday job-detail record; disabling descriptions reduces request count substantially on large Workday boards.

Company-domain discovery

When the ATS URL is unknown, pass a company home page or careers page in companyUrls. The Actor scans a small, bounded set of public pages and follows career-related links. Every discovered board and job keeps its origin URL and discovery-page provenance.

{
"boards": [],
"companyUrls": ["https://linear.app/careers"],
"outputMode": "changes",
"stateKey": "linear-watchlist"
}

The discovery result is written to the default key-value store as DISCOVERY_REPORT. A URL that cannot be resolved does not stop other companies by default. Set failOnDiscoveryError to true when complete discovery is required.

Monitor explicit ATS board URLs

Use changes mode for monitoring. The first run emits every current job as CREATED. Later runs return only jobs that appeared, changed, or closed.

{
"boards": [
{
"url": "https://job-boards.greenhouse.io/greenhouse",
"company": "Greenhouse"
},
{
"url": "https://jobs.lever.co/ae-2",
"company": "AE"
}
],
"outputMode": "changes",
"stateKey": "competitor-watchlist",
"includeDescriptions": true,
"includeCompensation": true,
"emitInitialSnapshotChanges": true
}

For continuous monitoring, save this input as an Apify task and run it on a schedule. Keep the same stateKey for that watchlist and do not overlap runs using the same key.

Input reference

FieldTypeDefaultDescription
boardsarray[]Board URL strings or { url, ats, slug, company } objects
companyUrlsstring[][]Company home or careers URLs to scan for supported ATS boards
catalogobjectdisabledBootstrap/process the bundled 10K candidate catalog and configure chunk/lifecycle rules
outputModestringchangeschanges, jobs, or both
stateKeystringdefaultSnapshot namespace; use a unique value per independent watchlist
includeDescriptionsbooleantrueReturn descriptions and detect description edits
includeCompensationbooleantrueNormalize salary data when exposed by the ATS
emitInitialSnapshotChangesbooleantrueEmit CREATED for every job on the first run
maxConcurrencyinteger10Boards fetched in parallel, from 1 to 50
requestTimeoutSecsinteger30Timeout for each request attempt
maxRequestRetriesinteger2Retries for rate limits, server errors, and network failures
failOnBoardErrorbooleanfalseFail the run instead of returning a partial result
discoveryMaxPagesinteger5Maximum public pages scanned for each company URL
failOnDiscoveryErrorbooleanfalseFail if any company URL cannot be resolved
freshnessSlaMinutesinteger10Source-to-detection SLA target used in freshness reports

At least one item is required across boards and companyUrls, unless catalog.enabled is true.

Output modes

  • changes - recommended for scheduled monitoring. Full jobs on the first run, then only changes.
  • jobs - every currently open job on every run.
  • both - open jobs followed by change records. This can produce two billable records for the same job on the first run.

Output example

The records below follow one real job on a real Recruitee career board through its lifecycle. The normalized job record and the CREATED event are unedited output from live scheduled runs on 2026-07-28. The UPDATED and CLOSED events were produced by the production change engine replaying the same board with one salary edit and one closure, because neither had yet occurred naturally on this board when this page was written; every field is real engine output. Long descriptions are shortened here.

1. Normalized job record (jobs mode)

One remote role posted across four locations, merged into a single record instead of four duplicates. The Cologne location activates DACH enrichment: structured locationDetails, dachRegion, a conservative KldB occupational group, and extracted language requirements. Fields the source does not publish stay null.

{
"recordType": "job",
"status": "OPEN",
"id": "fb650323dd54bfe995e5ed74be41edf3",
"jobKey": "recruitee:jobs:2659009",
"ats": "recruitee",
"boardSlug": "jobs",
"sourceJobId": "2659009",
"company": "Tellent",
"title": "Senior Backend Engineer (Node.js)",
"locations": [
"Remote job",
"Amsterdam, Noord-Holland, Netherlands",
"Cologne, Nordrhein-Westfalen, Germany",
"Poznań, Wielkopolskie, Poland"
],
"locationDetails": [
{
"raw": "Remote job",
"city": null,
"region": null,
"country": null,
"countryCode": null,
"isDach": false,
"isRemote": true
},
{
"raw": "Amsterdam, Noord-Holland, Netherlands",
"city": null,
"region": null,
"country": null,
"countryCode": null,
"isDach": false,
"isRemote": false
},
{
"raw": "Cologne, Nordrhein-Westfalen, Germany",
"city": "Cologne",
"region": "North Rhine-Westphalia",
"country": "Germany",
"countryCode": "DE",
"isDach": true,
"isRemote": false
},
{
"raw": "Poznań, Wielkopolskie, Poland",
"city": null,
"region": null,
"country": null,
"countryCode": null,
"isDach": false,
"isRemote": false
}
],
"dachRegion": "DE",
"primaryLocation": "Remote job",
"department": null,
"team": null,
"employmentType": "FULL_TIME",
"employmentTypeRaw": "fulltime_permanent",
"workplaceType": "REMOTE",
"workplaceTypeRaw": "remote",
"salary": null,
"descriptionText": "Note: The listed salary range is based on the salary range for the Netherlands. Salary ranges may vary by loca ...",
"descriptionHtml": "(HTML description, shortened here)",
"publishedAt": "2026-07-23T11:22:12.000Z",
"updatedAt": "2026-07-23T11:22:12.000Z",
"sourceUrl": "https://careers.tellent.com/o/senior-backend-engineer-nodejs",
"applyUrl": "https://careers.tellent.com/o/senior-backend-engineer-nodejs/c/new",
"boardUrl": "https://jobs.recruitee.com",
"sourceApiUrl": "https://jobs.recruitee.com/api/offers",
"boardOrigin": "explicit",
"discoveredFrom": null,
"companyId": "e4a478fc861a91b37c616f24",
"companyDomain": null,
"canonicalJobId": "4810f6bb90b4cd1e72be89863716be64",
"duplicateGroupId": null,
"isDuplicate": false,
"duplicateOf": null,
"kldb": {
"code": "43",
"title": "Informatik-, Informations- und Kommunikationstechnologieberufe",
"level": 2,
"version": "KldB 2010 – Fassung 2020",
"confidence": 0.9,
"method": "title-keyword-v1"
},
"languageRequirements": [
{
"language": "English",
"level": "C1",
"evidence": "rimary area of expertise. Strong communication skills and fluency in English. What we offer Hybrid or remote working setup across Amsterdam, the Cologne area, and Po"
}
],
"skills": [
"Node.js",
"React"
],
"firstSeenAt": "2026-07-28T12:27:33.329Z",
"lastSeenAt": "2026-07-28T12:27:33.329Z",
"scrapedAt": "2026-07-28T12:27:33.329Z"
}

2. CREATED and UPDATED change events (changes mode)

Every change event carries convenient top-level fields for tables plus the full normalized job in job. The CREATED event below is the real first observation of the job above.

{
"recordType": "change",
"eventType": "CREATED",
"eventId": "fa7c2b45bb559a4feaa57995a7914972",
"detectedAt": "2026-07-28T12:27:33.329Z",
"jobKey": "recruitee:jobs:2659009",
"ats": "recruitee",
"boardSlug": "jobs",
"company": "Tellent",
"title": "Senior Backend Engineer (Node.js)",
"primaryLocation": "Remote job",
"sourceUrl": "https://careers.tellent.com/o/senior-backend-engineer-nodejs",
"boardOrigin": "explicit",
"discoveredFrom": null,
"companyId": "e4a478fc861a91b37c616f24",
"canonicalJobId": "4810f6bb90b4cd1e72be89863716be64",
"duplicateGroupId": null,
"isDuplicate": false,
"duplicateOf": null,
"changedFields": [],
"job": "(full normalized job record embedded, identical to the record above)"
}

When the employer later publishes a salary range, the fingerprint diff emits exactly one UPDATED event, and changedFields names precisely what changed:

{
"recordType": "change",
"eventType": "UPDATED",
"eventId": "18f9d2662c7a695f4995e59fd2004de1",
"detectedAt": "2026-07-28T13:27:31.212Z",
"jobKey": "recruitee:jobs:2659009",
"ats": "recruitee",
"boardSlug": "jobs",
"company": "Tellent",
"title": "Senior Backend Engineer (Node.js)",
"primaryLocation": "Remote job",
"sourceUrl": "https://careers.tellent.com/o/senior-backend-engineer-nodejs",
"boardOrigin": "explicit",
"discoveredFrom": null,
"companyId": "e4a478fc861a91b37c616f24",
"canonicalJobId": "4810f6bb90b4cd1e72be89863716be64",
"duplicateGroupId": null,
"isDuplicate": false,
"duplicateOf": null,
"changedFields": [
"salary",
"updatedAt"
],
"job": {
"status": "OPEN",
"title": "Senior Backend Engineer (Node.js)",
"salary": {
"min": 65000,
"max": 80000,
"currency": "EUR",
"interval": "year",
"summary": "EUR 65,000 to 80,000 per year",
"source": "structured",
"confidence": 0.95
},
"firstSeenAt": "2026-07-28T12:27:33.329Z",
"lastSeenAt": "2026-07-28T13:27:31.212Z",
"note": "remaining job fields unchanged, shortened here"
}
}

3. CLOSED: what the feed guarantees when a job disappears

  • Explicit closure. The job's final known state is delivered with status: "CLOSED" and its complete firstSeenAt / lastSeenAt history, so downstream systems never have to infer closures from absence.
  • No stale content. Stored snapshots deliberately drop descriptions, so a CLOSED record reports them as null instead of replaying outdated text.
  • No false mass closures. A failed, throttled, or malformed board keeps its previous snapshot and emits no CLOSED events at all.
  • No noise. The unchanged third job on this board produced no record in the same run, and an immediate repeat run on an unchanged board writes zero rows and bills zero events (measured: a 22-role board billed 22 events on first observation, 0 on the repeat).
{
"recordType": "change",
"eventType": "CLOSED",
"eventId": "68f701d5a7f1d6fdfe428090d3c77b9e",
"detectedAt": "2026-07-28T13:27:31.212Z",
"jobKey": "recruitee:jobs:2650251",
"ats": "recruitee",
"boardSlug": "jobs",
"company": "Tellent",
"title": "Team Lead Customer Support - DACH",
"primaryLocation": "Remote job",
"sourceUrl": "https://careers.tellent.com/o/team-lead-customer-support-dach",
"boardOrigin": "explicit",
"discoveredFrom": null,
"companyId": "e4a478fc861a91b37c616f24",
"canonicalJobId": "a2862a89b543c4ad7f2bb7576fc9b217",
"duplicateGroupId": null,
"isDuplicate": false,
"duplicateOf": null,
"changedFields": [
"status"
],
"job": {
"recordType": "job",
"status": "CLOSED",
"id": "cfcce6be6280bf1e233895acbbcb511c",
"jobKey": "recruitee:jobs:2650251",
"ats": "recruitee",
"boardSlug": "jobs",
"sourceJobId": "2650251",
"company": "Tellent",
"title": "Team Lead Customer Support - DACH",
"locations": [
"Remote job",
"Poznań, Wielkopolskie, Poland"
],
"locationDetails": [
{
"raw": "Remote job",
"city": null,
"region": null,
"country": null,
"countryCode": null,
"isDach": false,
"isRemote": true
},
{
"raw": "Poznań, Wielkopolskie, Poland",
"city": null,
"region": null,
"country": null,
"countryCode": null,
"isDach": false,
"isRemote": false
}
],
"dachRegion": null,
"primaryLocation": "Remote job",
"department": null,
"team": null,
"employmentType": "FULL_TIME",
"employmentTypeRaw": "fulltime_fixed_term",
"workplaceType": "REMOTE",
"workplaceTypeRaw": "remote",
"salary": null,
"descriptionText": null,
"descriptionHtml": null,
"publishedAt": "2026-07-14T07:24:04.000Z",
"updatedAt": "2026-07-14T12:48:50.000Z",
"sourceUrl": "https://careers.tellent.com/o/team-lead-customer-support-dach",
"applyUrl": "https://careers.tellent.com/o/team-lead-customer-support-dach/c/new",
"boardUrl": "https://jobs.recruitee.com",
"sourceApiUrl": "https://jobs.recruitee.com/api/offers",
"boardOrigin": "explicit",
"discoveredFrom": null,
"companyId": "e4a478fc861a91b37c616f24",
"companyDomain": null,
"canonicalJobId": "a2862a89b543c4ad7f2bb7576fc9b217",
"duplicateGroupId": null,
"isDuplicate": false,
"duplicateOf": null,
"kldb": null,
"languageRequirements": [],
"skills": [],
"firstSeenAt": "2026-07-28T12:27:33.329Z",
"lastSeenAt": "2026-07-28T12:27:33.329Z",
"scrapedAt": "2026-07-28T12:27:33.329Z"
}
}

Company identity and cross-ATS duplicates

Jobs receive a deterministic companyId. Discovered boards use the input company domain; explicit boards fall back to a normalized company name. Across successful boards in the same run, likely duplicate jobs are clustered using normalized title, compatible location and employment type, description similarity, and publication timing.

The Actor does not silently delete duplicate records. It marks non-canonical members with isDuplicate=true, sets duplicateOf to the richer canonical source record, and gives every cluster member the same canonicalJobId and duplicateGroupId. Filter isDuplicate=false when a single-record feed is desired. Keeping the source records makes migration periods and partial board failures auditable.

DACH enrichment

Every job includes structured locationDetails and a dachRegion (DE, AT, CH, or MULTI) when a supported country or major city is recognized. Titles are mapped conservatively to the official two-digit occupational main groups from the KldB 2010 - revised 2020. The result includes its level, version, confidence, and the title-keyword-v1 method so it cannot be confused with an official individual-case coding decision.

languageRequirements extracts German, English, French, Italian, Dutch, and Spanish requirements with explicit CEFR levels or a normalized qualitative level. skills contains canonical matches for common engineering, data, cloud, enterprise, and go-to-market tools. When the ATS has no structured compensation, plausible EUR or CHF ranges can be recovered from salary-context sentences in the description. Every salary reports source and confidence.

Change detection and reliability

Each successfully fetched board receives its own snapshot in the persistent ats-job-change-feed-state key-value store. Business fields are fingerprinted individually, so UPDATED records identify exactly which normalized fields changed.

Safety behavior:

  • HTTP rate limits, server errors, and network failures are retried.
  • A malformed HTTP 200 response is rejected instead of interpreted as an empty board.
  • Failed boards keep their previous snapshot and emit no CLOSED events.
  • Location ordering is canonicalized for comparison to avoid false updates.
  • Snapshot state advances only after that board's complete output is stored.
  • If the run's maximum charge cannot cover a whole board, that board is deferred atomically. Increase the maximum charge and rerun; its prior snapshot remains intact.

The RUN_SUMMARY record reports discovery, successful, failed, and budget-deferred board counts. DISCOVERY_REPORT lists the pages scanned, resolved boards, and per-company errors.

Ten-minute monitoring and SLA

For a ten-minute feed, save the Actor input as an Apify task and create an exclusive schedule with cron expression */10 * * * *. Exclusive scheduling prevents a new run from starting while the prior one is still active. Keep one stable stateKey and use the same timezone for operational dashboards; UTC is the simplest default.

Every run writes FRESHNESS_REPORT to the default key-value store. It includes per-board fetch duration, source timestamp age, failures, and p50/p95/max detection latency. Baseline CREATED events are excluded. Later CREATED events use publishedAt, UPDATED events use updatedAt, and events without a compatible source timestamp are not presented as measured SLA samples. complianceRate=null therefore means “no measurable events,” not 0% compliance. Use publishing/examples/ten-minute-freshness-monitor.json as the task input.

Push changes into Make, n8n, or your own webhook

Add a webhook for the ACTOR.RUN.SUCCEEDED event (Actor page > Integrations). In scheduled changes mode a run's dataset contains only the new CREATED, UPDATED, and CLOSED records, so your endpoint receives the run notice and fetches exactly the delta in one call:

GET https://api.apify.com/v2/datasets/{resource.defaultDatasetId}/items?format=json&clean=1

In Make and n8n you can skip the webhook entirely: both have a native Apify integration with a run-finished trigger and a get-dataset-items action, so a scheduled monitor-then-notify flow takes two modules.

Pilot quality benchmark

Every run also writes QUALITY_REPORT. It measures board and discovery success rates, unique companies toward the 500-company pilot target, field completeness, ATS distribution, duplicate groups, DACH coverage, enrichment coverage, and errors grouped by ATS. This keeps the pilot exit criteria tied to observed data instead of a successful process exit alone.

The bundled pilot was generated from versioned public board candidates and validated on 26 July 2026. It selected 500 live boards across all eight adapters and normalized 15,923 open jobs. A rate-limited immediate repeat emitted zero observed changes or synthetic closures on successful sources. The same fixed 500-board list was then rechecked with per-provider concurrency limits: 500/500 boards succeeded and returned the same aggregate job count. The machine-readable reports and fixed input are included with the release artifacts.

Historical catalog candidates are never presented as verified companies. A candidate enters the live pilot only after its adapter returns a structurally valid response.

10,000-board catalog

Set catalog.enabled=true and catalog.bootstrapBundled=true to initialize the bundled 10,000-board candidate catalog. Its URLs were derived from versioned Common Crawl URL Index snapshots; every new record starts as PENDING, not ACTIVE.

{
"boards": [],
"companyUrls": [],
"catalog": {
"enabled": true,
"key": "production-10k",
"bootstrapBundled": true,
"process": true,
"chunkSize": 100
},
"outputMode": "changes",
"stateKey": "production-10k",
"includeDescriptions": false,
"includeCompensation": false,
"emitInitialSnapshotChanges": false,
"maxConcurrency": 20
}

The catalog uses PENDING, ACTIVE, RETRY, STALE, and EXPIRED states. Successful fetches activate an entry. Failures get a retry deadline without advancing the job snapshot. Repeatedly failing old entries become tombstoned EXPIRED records; a later company-domain rediscovery can reactivate them as PENDING.

Every catalog run writes CATALOG_REPORT and CATALOG_TASK_PLAN. The task plan contains a deterministic input for each chunk. A single rotating task does not provide ten-minute freshness across 10,000 boards; create one exclusive scheduled task per chunk, then verify account concurrency and CU cost in the cloud before enabling the full schedule.

StepStone scope decision

StepStone is intentionally not included as a ninth adapter. Its current general terms explicitly prohibit scraping content for another purpose, while its documented JobFeed API is a contracted customer/HR-tech interface for sending listings to StepStone rather than a public bulk-read API. The separate StepStone feasibility phase therefore triggered its predefined compliance stop-loss. No proxy, CAPTCHA bypass, or StepStone data collection code is shipped. Reconsider it only with written bulk-read/reuse permission or an appropriately licensed official read API.

Pricing behavior

The billable job-result event is one record written to the default dataset. In changes mode, unchanged jobs produce no result events at all - if nothing moved on a board, that run costs you nothing beyond the Actor start fee.

This is verified behaviour, not a claim: a first observation of a board with 22 open roles billed 22 events; the very next run against the same board found no changes and billed zero.

What daily monitoring actually costs

Free-plan example: one board with 500 open roles, checked every day for 30 days, with a typical ten changes a day:

Job or change eventsActor startTotal
Day 1 baseline$1.00$0.005$1.005
Each later day$0.02$0.005$0.025
30-day total$1.58$0.15$1.73

The first run bills the initial 500 records. The following 29 runs bill only ten changed records each, plus the start event on every run. Plan discounts can reduce these prices.

Apify's maximum total charge setting is respected, and the exact current prices are displayed in the Apify Store pricing section before every run.

Apify's maximum total charge setting is respected. This Actor does not silently advance a board's snapshot after withholding some of its results for budget reasons.

Use cases

  • Monitor target companies for new or closed roles
  • Build a job-board feed from primary company sources
  • Generate sales signals from hiring activity
  • Track competitor headcount priorities
  • Analyze role, location, salary, and remote-work changes
  • Create DACH-focused job alerts for Ausbildung, Werkstudent, or Minijob roles

This Actor is also exposed to AI agents through Apify's MCP server (mcp.apify.com): an agent can discover it by search and run it with the same pay-per-event billing, with no separate integration.

Data and privacy

This Actor reads public company job postings only. It does not:

  • log in to an ATS;
  • access internal jobs, candidates, applications, resumes, or contact details;
  • submit job applications;
  • send source data to an external enrichment service.

For company-domain discovery, it requests at most discoveryMaxPages public HTML pages per input URL. Private, local, credential-bearing, nonstandard-port, and private-DNS targets are rejected to prevent server-side request forgery.

Inputs, outputs, and snapshots remain in the Apify storages associated with the user's account. Users are responsible for ensuring their use of public job data complies with applicable laws and source-site terms.

Current limitations

  • Company-domain discovery reads public static HTML. JavaScript-only sites, custom career stacks, or pages without a supported ATS link can remain unresolved; provide an explicit board URL in those cases.
  • Company identity uses the discovered domain or normalized company name; legal-entity hierarchies and renamed/acquired companies can still require downstream overrides.
  • Duplicate detection is conservative metadata, not destructive suppression. Same-titled requisitions can require downstream review.
  • KldB, language, skill, location, and description-salary enrichment is deterministic heuristic metadata. It should be reviewed before regulated, statistical, or compensation decisions; the built-in city and skill dictionaries are intentionally bounded.
  • Source providers can change their public formats; partial-run safety prevents a format failure from creating false closures.
  • The bundled 10K catalog is a candidate inventory, not a claim that all 10,000 historical URLs are currently live. Lifecycle state and live fetch reports provide that distinction.
  • Full 10K/10-minute operation requires multiple scheduled tasks and enough cloud concurrency. Local benchmarks cannot substitute for the final account-specific CU and pricing check.
  • Snapshot writes are atomic per board, but dataset output and snapshot persistence cannot be committed as one cross-storage transaction. A crash between them can repeat an event.

Support

Open an issue on the Actor page with the board URL, run ID, expected behavior, and the relevant output field. Do not post API tokens, candidate information, or other secrets.