Job Postings Aggregator — ATS Evidence avatar

Job Postings Aggregator — ATS Evidence

Pricing

from $1.70 / 1,000 job postings

Go to Apify Store
Job Postings Aggregator — ATS Evidence

Job Postings Aggregator — ATS Evidence

Normalize current public job postings from known Greenhouse, Lever, or Ashby board tokens or bounded company-domain ATS detection. Rows include source evidence, attribution, freshness, confidence, gaps, billing semantics, and a manual review action. A listing does not prove growth or buying intent.

Pricing

from $1.70 / 1,000 job postings

Rating

0.0

(0)

Developer

Tim Zinin

Tim Zinin

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

11 days ago

Last modified

Share

Job Postings Aggregator — public ATS evidence for recruiting and company research

Turn known Greenhouse, Lever, or Ashby board tokens — or a list of company domains — into one normalized row per unique current job posting. Each delivered role carries a direct source link, retrieval evidence, freshness, company-board attribution, confidence, interpretation gaps, stable IDs, billing semantics, and a recommended manual review action.

Use the result to build recruiting shortlists, map where a market is hiring, enrich an account-research queue, or watch a portfolio of companies. Treat it as evidence that a role appeared on a public board at request time. A posting does not prove headcount growth, a new vacancy, budget, expansion, buying intent, or that the position will be filled.

Job Postings Aggregator turns known ATS tokens or company domains into unique current role rows with provenance freshness confidence gaps and a manual review action

What you get

  • Two ways in. Already know the ATS? Use items (provider:company tokens) — one HTTP call per company. Only know the company's domain? Use domains — this Actor checks the company's own careers page for its ATS, then verifies a slug guess if that fails. Mix both in the same run.
  • Six systems on the domain path. Greenhouse, Lever, Ashby, Workable, Rippling and Workday — items still covers the first three directly (unchanged, one request each); domains covers all six via automatic detection.
  • A domains role you can't vouch for still ships — just for free. When this Actor finds a company's ATS via the domain-slug fallback rather than a link on the company's own careers page, it checks that board's own declared owner against your domain before charging for it. Real example: atlas.com resolves to a genuine, non-empty Ashby board, but that board declares its own company website as atlascard.com — a different company most likely owns it, so every job from it is delivered in full and never billed. items roles are unaffected — you named the provider and slug yourself, nothing to verify. See Pricing and Output below.
  • Current role observations, normalized. Title, location, department, posting date and direct apply URL use one shape. Token mode reads a complete single-feed response within the documented 3 MB limit. Paginated Workday and Rippling domain results can reach a bounded read depth and disclose resolved-truncated instead of pretending the list is complete.
  • Evidence, not a black box. Successful role rows expose the source URL, retrieval time, HTTP status, response bytes, record count, ownership evidence, freshness, confidence reasons, known gaps, and a manual next action.
  • No login or private credentials. Token mode calls fixed public ATS JSON endpoints. Domain mode may first read public HTML on the submitted company's careers pages, then uses public ATS data. Requests are bounded and domain fetches use SSRF and DNS-rebinding guards.
  • Exact delivery and duplicate control. The same provider, board and job ID is delivered once even if it arrives through both items and domains. Paid delivery requires the exact linked Dataset/pay-per-event receipt; ambiguity stops the run with replaySafe: false instead of risking a second charge.
  • Built for lists. Concurrency up to 20, up to 100 companies per run per field, so tracking a whole sector's hiring is a single run.
  • Run-level reconciliation. KVS OUTPUT records requested and unique queries, successful and failed queries, paid and free rows, duplicate suppression, withheld work, partial state, fatal ambiguity, budget state, and replay safety.
  • Apify-native delivery. Schedule it, monitor it, call it from the API or MCP server, export JSON/CSV/Excel, or route results through webhooks, Make, Zapier, n8n, Sheets, a CRM staging table, or your own code.

Who buys this — and what they do with it

Recruiters and staffing agencies

Start from companies you already cover, retrieve their current public roles, filter by title, department and location, then open the cited job before contacting anyone. The value is faster market mapping and less manual careers-page checking — not an invented contact record or a guarantee that the employer wants agency help.

Small B2B agencies and founder-led sales teams

Add a current role observation to account research before a human decides whether the role creates a relevant question. A security role may justify researching the company's security program; it does not prove security-software budget or purchase intent. Combine the role with fit, relationship history, independent company context, suppression lists and lawful contact policy.

Market researchers and competitive-intelligence teams

Normalize public hiring pages across a buyer-defined company list. Schedule recurring runs and compare saved observations in your own warehouse to study listing changes. One run is a snapshot; this Actor deliberately does not call one snapshot a trend.

Investors, accelerators and portfolio operators

Review current role mix across a known portfolio or thesis list. Use department and location as research directions, then verify the source and company identity. Open roles are operational observations, not audited headcount, payroll, growth or financial guidance.

Data and RevOps teams

Use stable IDs, source evidence and KVS OUTPUT to stage results before CRM mutation. The Actor returns no personal email, phone number, applicant record or private ATS data. It is an enrichment component, not a fully qualified lead decision.

What this Actor is — and is not

It is a bounded collector and normalizer for public job-board observations. Direct token mode supports Greenhouse, Lever and Ashby. Domain detection can identify Greenhouse, Lever, Ashby, Workable, Rippling or Workday using a first-party careers-page link or a disclosed slug-guess fallback.

It is not a general web crawler, candidate database, contact finder, job-description scraper, applicant tracker, employer-of-record verifier, growth detector, intent-data provider or automatic outreach engine. It does not expose private applications, recruiter identities, salary when absent, filled-role outcomes, historical change by itself, or every ATS on the market.

Job Postings Aggregator workflow from known ATS tokens or company domains through bounded source validation ownership resolution cross mode deduplication and manual buyer review

How the evidence workflow works

  1. Validate before source work. Input must be an object containing 1–100 strings in items, domains, or both. Unsupported providers, malformed tokens, non-string values and fractional or out-of-range concurrency fail visibly instead of being silently coerced.
  2. Deduplicate with provider semantics. Greenhouse and Ashby board tokens are case-folded because those paths are case-insensitive; Lever case is preserved. Domains are normalized. Duplicate input count is written to OUTPUT.
  3. Request only what you selected. Token mode calls the fixed public provider endpoint. Domain mode checks guarded public company pages and bounded ATS candidates. Mixing the modes is supported.
  4. Fail closed on source shape. Responses have a 20-second timeout and a 3 MB token-mode cap. Content type and provider-specific JSON shape are validated. Truncated or malformed HTTP‑200 responses become source errors, never believable empty boards.
  5. Resolve and disclose identity. A first-party careers-page link is retained as primary evidence. Slug guesses are checked against ATS-declared owner signals; mismatch or inconclusive attribution is delivered free for manual review.
  6. Normalize without inflating the claim. Provider fields map to title, location, department, URL and posted time. Stable entity, observation, event and evidence IDs are attached.
  7. Suppress cross-mode duplicates. Delivery identity uses provider, canonical board token and job ID or URL. The same job discovered from both input paths is not delivered or charged twice.
  8. Attach decision context. Every successful job row explains freshness, single-observation change semantics, evidence coverage, confidence reasons, data gaps, billing status, and the next manual action. safeToAutomate is always false.
  9. Deliver and reconcile. Paid rows use one linked Dataset/PPE call. The runtime requires the exact Apify aggregate receipt. Any ambiguous push or receipt is fatal, not automatically replayed, and appears in OUTPUT with replaySafe: false.

How to run it

  1. Click Try for free — no card needed on the free plan.
  2. Either paste provider:company tokens into Companies (ATS tokens) (e.g. greenhouse:stripe, lever:spotify, ashby:ramp), or paste bare domains into Companies (bare domains) (e.g. figma.com, ramp.com) — or both.
  3. Press Start. Results appear in the dataset — read them in the UI, pull them from the API, or have a webhook push them onward.

Pricing

Pay-per-event: $0.005 per run start + $0.002 per role found. No monthly seat, no minimum. 100 roles cost about $0.21; 1,000 roles about $2.01. items roles are always billed at this rate — you named the ATS yourself, nothing to verify. A domains role resolved via its own careers-page link (Method A) is billed the same way — the company already named this board itself.

A company with no public board (items) or a domain this Actor could not resolve to any ATS (domains) is still logged with found: false and the reason — and it is not charged for.

One more free case, added 04.08.2026, domains only: when this Actor identifies a company's ATS via the domain-slug fallback (Method B) instead of its own careers-page link, it checks that board's own declared owner against the domain you asked for before billing the role. Confirmed match — billed, same as always. Confirmed mismatch, or the check itself couldn't be run — the role still ships to your dataset in full, just never billed. Real example: atlas.com resolves to a genuine, non-empty Ashby board, but that board's own page declares its company website as atlascard.com, not atlas.com — every job from it is free. See the atlas.com row in Output below, and FAQ for what this check can and can't prove. This never applies to items — you pay for roles actually delivered via a board you named yourself, or one this Actor confirmed (or found first-party) belongs to the domain you asked for.

Input

FieldRequiredWhat it does
itemsno*One entry per company, format provider:company. Provider is greenhouse, lever or ashby; company is the board's own slug (the part in the careers URL, e.g. jobs.lever.co/spotifyspotify). Up to 100 per run.
domainsno*One entry per company, a plain domain or full URL — no need to know its ATS. Detected automatically (Greenhouse, Lever, Ashby, Workable, Rippling or Workday). Up to 100 per run.
maxConcurrencynoHow many companies to check in parallel, 1–20 (default 5). Applies to the combined workload of items + domains.

* At least one of items or domains must have an entry.

{
"items": [
"greenhouse:stripe",
"lever:spotify",
"ashby:ramp"
],
"domains": [
"figma.com",
"ramp.com"
]
}

Output

One dataset row is delivered per unique current role observation. Free diagnostic rows explain unresolved, empty, truncated or failed inputs. The compatibility fields stay intact; the evidence and decision fields are additive. This is a real items row from an earlier production run (the newer evidence fields shown after it are generated from that observation at runtime):

{
"input": "greenhouse:airtable",
"found": true,
"provider": "greenhouse",
"company": "airtable",
"jobId": "8391589002",
"title": "Account Executive, SLED",
"location": "Austin, TX; Remote - US",
"department": null,
"url": "https://job-boards.greenhouse.io/airtable/jobs/8391589002",
"postedAt": "2026-01-26T22:00:52.000Z",
"attributionConfirmed": null,
"attributionNote": "Provider and slug were specified directly on input — this Actor performed no domain resolution or ownership verification for this row.",
"scrapedAt": "2026-08-04T16:48:07.640Z"
}

The same successful observation now also carries this machine-readable decision context:

{
"inputMode": "token",
"entityId": "job_<stable hash of provider, board and job>",
"observationId": "observation_<stable hash of job and observation time>",
"eventId": "event_<stable hash>",
"observedAt": "<run observation time>",
"freshness": {
"observedAt": "<run observation time>",
"postedAt": "2026-01-26T22:00:52.000Z",
"postedAgeDays": "<calculated integer or null>",
"basis": "live_public_ats_board_at_request_time"
},
"change": {
"basis": "single_observation",
"previousObservationAvailable": false,
"delta": null
},
"evidence": [{
"evidenceId": "evidence_<stable hash>",
"provider": "greenhouse",
"url": "https://boards-api.greenhouse.io/v1/boards/airtable/jobs?content=false",
"retrievedAt": "<source retrieval time>",
"httpStatus": 200,
"contentType": "application/json",
"responseBytes": "<measured bytes>",
"outcome": "ok",
"recordCount": "<validated role count>"
}],
"evidenceCoverage": 100,
"confidence": {
"score": 70,
"level": "medium",
"reasons": [
"The buyer supplied the ATS provider and board token directly; company ownership was not independently verified.",
"Machine-readable retrieval or resolution evidence is attached."
]
},
"recommendedAction": "Open the cited role, confirm company and posting context, then use it as one research input rather than an automated intent signal.",
"safeToAutomate": false,
"billing": {
"event": "result-found",
"billable": true,
"unit": "one_confirmed_delivered_job_posting_row"
},
"observationSemantics": {
"observed": "A role currently appeared on the selected public ATS board at request time.",
"doesNotProve": ["headcount growth", "new hiring demand", "budget", "business expansion", "buying intent", "role fulfillment"]
}
}

Note attributionConfirmed: null here — on an items row that means "not applicable", and the row is billed exactly as normal (found: true). It reads the same as a domains row's "couldn't verify" null, but the two are never the same claim — see the field table above and the atlas.com row below for the domains-mode meaning of null.

FieldWhat it means
inputThe provider:company token or domain you passed
foundtrue marks a billed row, false a free one. Before 04.08.2026 this meant "the board returned at least one open role"; as of the case below, a genuine domains role (real title/url/jobId) can carry found: false when it was delivered free-by-policy — see atlas.com below. Every items role and every Method A domains role is still found: true.
providergreenhouse, lever, ashby, workable, rippling or workday
companyThe board's company slug (typed directly via items, or auto-detected via domains)
jobIdThe ATS's internal job ID
titleRole title
locationOffice/remote location as listed
departmentTeam/department as listed, when the board publishes one
isRemoteWhether the role is remote — only set on rows found via domains; absent on items rows
urlDirect apply/posting URL
postedAtISO timestamp of when the role was first published
resolvedViaHow a domains row's ATS was identified: careers-page (Method A, found a direct link on the company's own site) or slug-guess (Method B, verified by real, non-empty postings). Absent entirely on items rows — that absence is what tells the two input modes apart when attributionConfirmed reads null on both (see below).
attributionConfirmedOnly meaningful when resolvedVia is present (i.e. a domains row). true on every Method A row and on a Method B row whose board declared owner matches your domain — both billed. false on a Method B row whose declared owner names someone else — free (the atlas.com row below). null on a Method B row where the check could not be run at all — also free, a different fact from false, never conflated with it. On an items row, attributionConfirmed also reads null, but means something else entirely: "not applicable" — you named the provider and slug directly, there was nothing to verify, and the row is billed normally. Check resolvedVia's presence, not the value of attributionConfirmed alone, to tell these two nulls apart.
attributionNoteHuman-readable explanation of the value above. On an items row it says plainly that no resolution or ownership verification was performed for this row.
scrapedAtWhen this Actor fetched the row
inputModetoken or domain; use this instead of inferring the path from attribution fields
entityIdStable job identity derived from provider, board and job ID or URL; useful for joins and cross-run storage
observationIdStable identity for this job at this run's observation time
eventIdStable identity for the open-role observation event
observedAtOne run-level timestamp applied consistently to this observation
freshnessObservation time, provider-supplied posting time, calculated age when possible, and the freshness basis
changeExplicitly says this row is a single observation with no built-in prior baseline or fabricated delta
evidenceSource or resolution receipts with stable evidence IDs, URL, retrieval time, response facts, outcome and count when observable
evidenceCoverageCoverage score for attached machine-readable source evidence; not a probability that the employer will hire
confidenceScore, level and reasons about the observation and attribution; separate from commercial fit or intent
dataGapsImportant facts this source cannot establish, including growth, budget, intent and role outcome
recommendedActionManual verification or research step appropriate to the row's attribution state
safeToAutomateAlways false; this observation alone is not sufficient for autonomous CRM mutation or outreach
billingWhether the row is billable, the event name or null, exact commercial unit and reason
observationSemanticsCompact statement of what was observed and which stronger conclusions are unsupported

Domain mode — confirming a board actually belongs to the domain you asked for

A domains role found via the slug-guess fallback (Method B) is real and non-empty the moment it's found, but that alone doesn't prove the board belongs to the domain you asked for. Before billing it, this Actor checks the board's own declared owner against your domain. Confirmed — real row, figma.com, resolved via its own careers-page link (Method A, always billed, nothing to check):

{
"input": "figma.com",
"found": true,
"provider": "greenhouse",
"company": "figma",
"jobId": "5364702004",
"title": "Account Executive, Emerging Enterprise (Berlin, Germany)",
"location": "Berlin, Germany",
"department": null,
"isRemote": false,
"url": "https://boards.greenhouse.io/figma/jobs/5364702004?gh_jid=5364702004",
"postedAt": "2024-11-01T10:05:10.000Z",
"resolvedVia": "careers-page",
"attributionConfirmed": true,
"attributionNote": "The company's own careers page linked directly to this job board — primary-source evidence, nothing left to independently verify.",
"scrapedAt": "2026-08-04T16:48:09.880Z"
}

Not confirmed — real row, atlas.com, same run, Method B, delivered but free (

found: false
on a row with a real title, real jobId, real url — never withheld, only unbilled):

{
"input": "atlas.com",
"found": false,
"provider": "ashby",
"company": "atlas",
"jobId": "dae00fcb-35a5-4559-8114-7553138b3ea3",
"title": "Founding Applied AI Engineer",
"location": "San Francisco",
"department": "Engineering",
"isRemote": false,
"url": "https://jobs.ashbyhq.com/atlas/dae00fcb-35a5-4559-8114-7553138b3ea3",
"postedAt": "2026-02-24T18:52:51.098Z",
"resolvedVia": "slug-guess",
"attributionConfirmed": false,
"attributionNote": "Ashby's job board declares its own company website as atlascard.com, which does NOT match the requested domain atlas.com — this board most likely belongs to a different company.",
"scrapedAt": "2026-08-04T16:48:11.460Z"
}

A third case, just as free but a different fact: attributionConfirmed: null on a domains row (resolvedVia still present) means this Actor could not tell either way — either the check couldn't be run at all, or the board's declared name is inconclusive rather than confidently wrong. That second flavor is real and live: chime.com resolves to its own, genuine Greenhouse board — the company never changed its name — but that board is legally named "Chime Financial, Inc", not "Chime":

{
"input": "chime.com",
"found": false,
"provider": "greenhouse",
"company": "chime",
"jobId": "8609153002",
"title": "Analyst, Investor Relations",
"location": "San Francisco, CA, USA",
"department": null,
"isRemote": false,
"url": "https://boards.greenhouse.io/chime/jobs/8609153002?gh_jid=8609153002",
"postedAt": "2026-07-22T18:36:41.000Z",
"resolvedVia": "slug-guess",
"attributionConfirmed": null,
"attributionNote": "Greenhouse's job board is named \"Chime Financial, Inc\", which STARTS WITH the requested domain chime.com but adds a real word this Actor does not strip (a business descriptor, not legal boilerplate) — this looks like it could be your company, but a name alone does not prove it: Greenhouse does not publish this board's owner website, and a genuinely unrelated company with a similar name would read exactly the same way.",
"scrapedAt": "2026-08-04T17:32:04.760Z"
}

This is deliberately null, not false: "Chime Financial, Inc" reads as a genuine match to anyone who knows the company, but this Actor can't tell that apart from a genuinely unrelated company that merely shares a leading word — pulse.com's own real Greenhouse board is named "Pulse Healthcare", the identical shape, and really is a different company (the actual Pulse is runpulse.com). By name alone these two cases can't be told apart, so neither gets more confidence than this Actor actually has. See FAQ below for what this check can and cannot prove.

Domain mode — when a company can't be resolved

A domains entry that doesn't turn into any job rows still gets exactly one free row, with found: false and a resolutionStatus that says why — never lumped into a generic "not found":

{
"input": "some-company.com",
"found": false,
"provider": null,
"company": null,
"resolutionStatus": "unresolved",
"error": "could not identify this company's applicant-tracking system...",
"scrapedAt": "2026-08-04T15:20:40.574Z"
}
resolutionStatusMeaning
resolved-zeroFound the company's ATS board — it genuinely has 0 open roles right now
unresolvedCould not identify an ATS for this domain — NOT the same as "no jobs", just "don't know"
source-errorEvery attempt failed to even reach a server (network/timeout) — NOT a confirmed "no ATS", retry later
invalid-domainThe entry didn't look like a real domain — no network call was made
resolved-truncatedThe board paginates (Workday/Rippling) and had more roles than this Actor's default read-depth — the rows already delivered are real, just possibly incomplete

Run reconciliation in KVS OUTPUT

The Dataset answers “which rows were delivered?” KVS OUTPUT answers “did the whole run finish cleanly, and is a replay safe?” Check both before downstream automation.

{
"status": "COMPLETE",
"observedAt": "<run observation time>",
"requestedQueryCount": 3,
"uniqueQueryCount": 3,
"duplicateInputCount": 1,
"processedQueryCount": 3,
"successfulQueryCount": 3,
"failedQueryCount": 0,
"unprocessedQueryCount": 0,
"observedJobCount": 127,
"confirmedDeliveredJobCount": 127,
"paidJobCount": 127,
"freeByAttributionPolicyJobCount": 0,
"localNonMonetizedJobCount": 0,
"duplicateJobCount": 8,
"withheldJobCount": 0,
"statusRowCount": 0,
"statusDeliveryFailureCount": 0,
"partial": false,
"budgetStopped": false,
"fatalError": null,
"replaySafe": true,
"billing": {
"monetized": true,
"event": "result-found",
"linkedReceiptExpectedChargedCount": 2,
"datasetItemPriceUsd": 0
}
}
  • COMPLETE means all unique queries were processed without failed queries or withheld work.
  • PARTIAL means at least one source query failed or work remained. Keep the valid rows, inspect status rows and retry only the affected inputs.
  • FATAL means delivery, billing or budget state became ambiguous. replaySafe is false; inspect the Dataset and charged events before any retry.
  • budgetStopped: true means the buyer's run cap stopped remaining paid delivery. Already delivered rows remain valid; withheld rows were not delivered or charged.
  • duplicateJobCount counts successful jobs suppressed across token/domain paths, not source failures.

Integration recipes

Apify API

Send input to the Actor run endpoint, wait for completion, then read the default Dataset and KVS OUTPUT. Keep your Apify token in a secret manager or platform integration — never hard-code it into a public workflow.

curl -X POST \
"https://api.apify.com/v2/acts/zinin~job-postings-aggregator/runs?token=$APIFY_TOKEN&waitForFinish=300" \
-H 'Content-Type: application/json' \
-d '{
"items": ["greenhouse:stripe", "lever:spotify"],
"domains": ["figma.com"],
"maxConcurrency": 5
}'

For unattended use, retain the returned run ID. Read the run's defaultDatasetId for rows and defaultKeyValueStoreId record OUTPUT for reconciliation. Do not treat an HTTP-successful run request as proof that every source query succeeded.

JavaScript

import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('zinin/job-postings-aggregator').call({
domains: ['figma.com', 'ramp.com'],
maxConcurrency: 5,
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
const output = await client.keyValueStore(run.defaultKeyValueStoreId).getRecord('OUTPUT');
if (output?.value?.replaySafe === false) {
throw new Error('Inspect Dataset and charged events before retrying this run');
}
const reviewQueue = items.filter((row) => row.jobId && row.safeToAutomate === false);

Python

import os
from apify_client import ApifyClient
client = ApifyClient(os.environ['APIFY_TOKEN'])
run = client.actor('zinin/job-postings-aggregator').call(run_input={
'items': ['ashby:ramp'],
'maxConcurrency': 3,
})
rows = list(client.dataset(run['defaultDatasetId']).iterate_items())
output_record = client.key_value_store(run['defaultKeyValueStoreId']).get_record('OUTPUT')
output = output_record['value'] if output_record else None

Google Sheets or Excel

Export the Dataset from the Apify console as CSV or Excel. Recommended review columns are company, title, location, postedAt, observedAt, confidence.level, attributionConfirmed, url, recommendedAction and dataGaps. Store entityId as text so spreadsheet formatting does not alter it.

n8n, Make, Zapier or webhooks

Trigger the Actor on a schedule or from a new company-list event. Wait for the run to finish, read KVS OUTPUT, then branch:

  1. continue only when status is COMPLETE or when your workflow explicitly accepts documented partial results;
  2. send rows into a staging table, not directly into an outreach sequence;
  3. deduplicate downstream on entityId and preserve observationId for history;
  4. require a human to open url, inspect evidence and confirm company context;
  5. apply your own consent, suppression, territorial and contact-policy checks before CRM or messaging actions.

MCP and AI-agent workflows

An agent can call this Actor through Apify's MCP surface, but the returned row is designed as research evidence, not an autonomous sales instruction. Keep safeToAutomate: false in the prompt context, preserve citations, and require human approval before updating a CRM record or contacting a person.

Scheduling and historical comparisons

To monitor a fixed market, create an Apify schedule with the same normalized company inputs and save each run ID. Compare rows by entityId; compare observations by observationId. A job present this week and absent next week is a candidate non-observation, not proof that the role was filled, cancelled or removed permanently. Provider outages, changed board tokens, pagination depth and attribution changes remain alternative explanations.

A practical weekly workflow is: preserve raw rows → verify OUTPUT → compare stable IDs → inspect added and missing candidates → open the source → annotate the human conclusion. This Actor supplies the first three ingredients; it does not manufacture the last two.

Responsible use, privacy and source limits

  • Submit only public company domains and public ATS board identifiers you are authorized to research.
  • Respect the source websites' terms, applicable law, contractual restrictions and your organization's data-retention policy.
  • Results concern public job postings. Do not combine them with sensitive applicant data, infer protected traits, or use them to make employment decisions about individuals.
  • The Actor does not collect applications, resumes, private candidate records, personal emails or phone numbers.
  • Public availability does not create permission to contact a company or person. Apply consent, suppression and jurisdiction-specific marketing rules separately.
  • Store source URLs, evidence and observation times with any derived conclusion so another reviewer can audit it.
  • Do not label a company “growing,” “funded,” “hiring urgently” or “ready to buy” solely from these rows.
  • Source systems can change, remove fields, return stale postings, rate-limit requests or expose incomplete data. Use evidence, resolutionStatus, dataGaps and OUTPUT instead of hiding those limitations.

Related tools for adjacent workflows in jobs and hiring.

ActorWhat it does
Company Hiring RadarPair it in the jobs and hiring workflow: Pull every open role a company is hiring for from its public job board (Greenhouse, Lever, Ashby) and turn...
XING Jobs (DACH) ScraperPair it in the jobs and hiring workflow: Walk xing.com's own job sitemap and pull public job listings from Germany/Austria/Switzerland: title,...
jobs.ch Swiss Jobs ScraperPair it in the jobs and hiring workflow: Search jobs.ch (Switzerland) by keyword and get public job listings: title, company, location, employment...
Layoff TrackerPair it in the jobs and hiring workflow: Track recent tech layoffs by company name or sector (e.g. "fintech", "AI") straight from Google News — a...
Computrabajo LatAm Jobs ScraperPair it in the jobs and hiring workflow: Search Computrabajo (Mexico, Colombia, Chile, Argentina, Peru) by keyword and get public job listings:...

FAQ

Does it need an API key / login? No — every ATS this Actor talks to (Greenhouse, Lever, Ashby, Workable, Rippling, Workday) publishes its job board as public keyless JSON.

How fresh is the data? Live at request time — the same feed that powers the company's own careers-page widget.

What if a company has no public board on a given provider (items), or its ATS can't be identified (domains)? The row says so (found: false, plus resolutionStatus on a domains row) instead of failing the whole run, and it's never billed.

How does the ownership check on domains work, and what can't it prove? Once the slug-guess fallback (Method B) already found a real, non-empty board, this Actor takes one more step before billing the role: it reads the board's own declared owner and compares it to the domain you asked for. Ashby publishes a real second domain (publicWebsite) — atlas declares atlascard.com, which is how this Actor knows atlas.com most likely isn't the real owner. Greenhouse, Lever, Workable and Rippling only publish a company name, not a second domain — so on four of these five providers, a coincidental name match (an unrelated real company that happens to share a name with the one you asked about) could in principle still pass; there is no stronger evidence those four APIs publish. This check never runs on items (you named the board yourself — attributionConfirmed reads null meaning "not applicable", not "unverified", see Output above) and never runs on a domains role resolved via its own careers-page link (Method A — already primary-source evidence).

Why does chime.com come back attributionConfirmed: null instead of true, when it's genuinely Chime's own board? Because the board's declared name is legally "Chime Financial, Inc" — this Actor's name comparison strips real legal suffixes (Inc, Ltd, GmbH...) but deliberately does not strip ordinary business words like "Financial" (a growing strip-list eventually swallows a real brand word too). The name starts with the requested domain's own label plus a real word this Actor won't guess past, so it lands as inconclusive — never a confident true, never a confident false either. It can't become true because pulse.com's own real board is named "Pulse Healthcare" — the identical shape — and is a genuinely different company; by name alone a "Brand + business word" board can't be told apart from one that belongs to someone else. You still get every role from a null board in full — see Pricing above.

items or domains — which should I use? If you already know the ATS, items is one HTTP call per company — use it. If you only know the company's domain, use domains; it costs a few extra requests per company to identify the ATS (still never billed on failure), then aggregates the same way.

Can I call it from an AI agent? Yes — standard Apify Actor, callable from the Apify API, the SDK, or the Apify MCP server.

What this is NOT. It does not cover ATS platforms beyond the six above (SmartRecruiters, Recruitee and Personio are deliberately excluded — their robots.txt disallows automated collection), and it does not read the full job description text. domains reads up to a fixed depth on paginated boards (Workday, Rippling) — see resolved-truncated above; for a configurable read-depth on very large paginated boards, use this Actor's sibling, Careers Page Scraper. Not a guarantee that a billed domains Method-B role's board is provably yours on every provider — Ashby's check compares a real domain, but Greenhouse, Lever, Workable and Rippling only ever expose a company name to check against, the strongest evidence those four systems publish (see FAQ); when even that name doesn't match, the role ships anyway, just free.

Found a wrong result, or need a check we don't run? Open an issue on this Actor's page.


Built by zinin. Questions? Telegram @timzinin.