sfoln/hiring-signals · Jobs, Lead generation, Automation On request
Hiring signals for any company: give a domain, careers page or job board and get one snapshot of its open roles from Greenhouse, Lever, Ashby and 8 more ATS: counts by department, location and seniority, remote share, salary bands, new roles in 7/30/90 days, velocity. $8 per 1,000.
Get hiring signals for any company from its own job board: give a website domain, a careers page or a job board URL and get one snapshot of the company's open roles: how many, which departments, locations, countries and seniority levels, the remote share, salary bands per department, how many roles were posted in the last 7, 30 and 90 days, the most common titles and a hiring-velocity score. The job board is found automatically on Greenhouse, Lever, Ashby, SmartRecruiters, Recruitee, Personio, Teamtailor, Breezy HR, BambooHR, Workable and Workday. Built for B2B sales teams (hiring is a buying signal), recruiters and staffing agencies, investors tracking growth, competitive intelligence and AI agents.
Price
Price per delivered record
Event
Price
Per 1,000
Charged for
Hiring snapshot hiring-snapshot
$0.008
$8 / 1,000
One company's hiring snapshot: open roles by department, location, seniority and workplace type, remote share, salary bands, roles posted in the last 7/30/90 days, top titles and a hiring-velocity score.
Apify free plan: up to 10 items per run. Paid plans have no per-run cap; set maxTotalChargeUsd to cap spend.
Run
Call it from code, an agent or the Console
This API is private on Apify for now. Email us and we will publish it for you, usually within two working days. The calls below work once it is public. contact@sfoln.com
POST https://api.apify.com/v2/actors/sfoln~hiring-signals/runs?maxTotalChargeUsd=1
GET https://api.apify.com/v2/actor-runs/{runId} # until status is SUCCEEDED
GET https://api.apify.com/v2/datasets/{defaultDatasetId}/items?format=json
Authenticate with an Apify API token. MCP clients can instead sign in with OAuth when prompted. Example prompt for an agent: Get hiring signals for stripe.com and ramp.com: how many open roles each has, which departments are growing, how many roles were posted in the last 30 days and their salary bands.
Input
Input fields
Add companies as website domains, careers pages, job board URLs or <ats>:<token>. Each company produces one hiring snapshot.
Field
Type
Default
Meaning
companies *
array
required
Companies (domains, careers pages or job boards) One per line: a company website (stripe.com: the job board is found from its links, its careers page or its name), a careers page, a job board URL (https://jobs.lever.co/palantir, https://boards.greenhouse.io/stripe, https://jobs.ashbyhq.com/ramp …) or <ats>:<token> such as greenhouse:stripe or ashby:ramp. Duplicates are removed. Accounts on the Apify free plan can process up to 10 companies per run.
maxJobsPerCompany
integer
2000
Max open roles analyzed per company Open roles read per company (1–10,000). Boards larger than this get a snapshot of the first roles read and a warning. Range 1–10000.
includeJobs
boolean
false
Include the job list Add a jobs array (up to 500 roles: title, department, locations, workplace type, seniority, salary, posting date, URL) to each snapshot. No extra charge.
includeWorkday
boolean
false
Read Workday career sites Workday sites (*.myworkdayjobs.com) are read through an undocumented endpoint, at most 200 jobs per site and 1 request per second. Off by default: such companies are skipped (not charged).
guessBoards
boolean
true
Guess the board from the domain When the website links to no supported job board, try the company's domain name as a board name on Greenhouse, Lever, Ashby, Recruitee, Personio, Teamtailor, Breezy, SmartRecruiters and BambooHR (snapshots say detectedBy: slug_guess). Not tried for IP addresses or sites on hosting platforms (*.vercel.app, *.github.io, *.wordpress.com …).
maxCompanies
integer
1000
Max companies Safety cap on the number of companies processed in this run. Range 1–10000.
concurrency
integer
4
Concurrency How many companies are processed in parallel (1–8). Requests to each ATS are rate-limited for the whole run. Range 1–8.
itemTimeoutSecs
integer
300
Time limit per company (seconds) Reading one company's board stops cleanly shortly before this limit (60–3600); the snapshot then covers the roles read. Range 60–3600.
includeRaw
boolean
false
Include raw upstream response Attach the ATS's original job objects (up to 200) to each snapshot (much larger output).
Records land in the run's dataset; a synchronous call returns them directly. Each has a status (ok is charged; everything else is free) and a charged flag. The run's OUTPUT record totals items and charges.
Field
Type
Meaning
input
string | object
Input The company entry as given.
company
string | null
Company Company name from the board, else the board token.
companyDomain
string | null
Company domain The website given, else the most common company domain of the job URLs.
Detected by input (board given) | careers_page (linked from the website or careers page) | slug_guess (domain name tried on the ATS APIs)
otherBoards
array
Other boards Further boards the website linked to.
jobsComplete
boolean
All roles read False when the board had more roles than maxJobsPerCompany or the time limit (a warning says so).
openJobs
integer
Open roles
departmentsCount
integer
Departments
byDepartment
object
Roles by department Department → open roles, most first (25 departments; the rest under "(other)").
byLocation
object
Roles by location Location → open roles (a role with several locations counts in each; 20 locations, the rest under "(other)").
byCountry
object
Roles by country ISO 3166-1 alpha-2 country → open roles ("unknown" when the location does not tell).
bySeniority
object
Roles by seniority (guess) intern, entry, mid, senior, lead, manager, director, vp, executive, unknown → open roles.
byWorkplaceType
object
Roles by workplace type remote, hybrid, onsite, unknown → open roles.
byEmploymentType
object
Roles by employment type full_time, part_time, contract, temporary, internship, volunteer, other, unknown → open roles.
remoteShare
number | null
Remote share Remote roles among roles with a known workplace type (0–1).
hybridShare
number | null
Hybrid share Hybrid roles among roles with a known workplace type (0–1).
salaryCoverage
number | null
Salary coverage Share of open roles that publish a salary (0–1).
salaryRange
object | null
Salary range { currency, min, max, median, jobs }: annualized salaries of all roles in the most common currency; a range more than 10× above or below the median of 3 or more ranges is left out.
salaryByDepartment
array
Salary by department [{ department, currency, min, max, median, jobs }] annualized (hourly × 2,080, monthly × 12), up to 15 departments.
postedLast7Days
integer
Posted in the last 7 days
postedLast30Days
integer
Posted in the last 30 days
postedLast90Days
integer
Posted in the last 90 days
jobsWithPostedDate
integer
Roles with a posting date
newestPostedAt
string | null
Newest posting
oldestPostedAt
string | null
Oldest open posting
medianJobAgeDays
integer | null
Median role age (days)
topTitles
array
Top titles [{ name, count }]: the 10 most common titles without seniority words and suffixes.
Jobs Only with includeJobs: up to 500 roles { jobId, title, department, team, locations, country, workplaceType, employmentType, seniority, salary, postedAt, url }.
status
string
Status ok | not_found | error | skipped_invalid | skipped_budget | skipped_free_plan | skipped_unmetered e.g. "ok"
charged
boolean
Charged Whether this record incurred a pay-per-event charge (hiring-snapshot).
chargedEvent
string
Charged event Pay-per-event event charged for this record (present only when charged).
chargedCount
integer
Events charged Events actually charged when the charge came back short of the requested count (present only then; a warning explains it).
source
string
Source Upstream data source (ats).
fetchedAt
string
Fetched at ISO timestamp.
error
object
Error { code, message, provider?, status? } when status is not ok. Actor codes: invalid_input, board_not_found, workday_not_enabled. Upstream codes: not_found (unknown board), http_error (see status), timeout, network, dns_not_found, too_large, invalid_json, unexpected_type, invalid_response. Codes set by the runtime: budget_exhausted, free_plan_limit, unmetered, aborted, charge_failed, record_too_large, invalid_record, dataset_push_failed.
warnings
array
Warnings Notes, e.g. a snapshot that covers only part of a very large board, or a website page that could not be read.
The Actor reads the website and its careers page and looks for links and embeds of Greenhouse, Lever, Ashby, SmartRecruiters, Recruitee, Personio, Teamtailor, Breezy, BambooHR, Workable and Workday. When none is linked it tries the domain name as a board name (detectedBy: slug_guess) and keeps a guess only when the board has jobs and its company name, where the ATS reports one, matches the domain.
What is the hiring-velocity score?
A 0–100 score: half from how many roles were posted in the last 30 days (reaching the maximum at 50 roles), half from the share of open roles posted in the last 30 days. Labels: none (0), low (under 25), moderate (under 50), high (under 75) and very_high. When a board gives no posting dates the score is based on the number of open roles (basis: open_roles).
Am I charged for companies without a job board?
No. Companies without a detectable board, unknown boards and errors return status not_found or error and are not charged. A company whose board exists but has no open roles gets a snapshot with openJobs: 0, which is charged.