Company Hiring Signals API: open roles, departments, locations
Coming soon to the StoreIs a company hiring, for what, where and since when? Give company names, domains or job board URLs; get one summary per company (open roles by department, location and country, remote share, newest and oldest posting dates, top titles) plus the open jobs, each with a link to the posting. Built for AI agents doing sales prospecting, recruiting or market research, and for people who want hiring data without scraping LinkedIn or Indeed.
Pricing (pay per event): $0.005 per company summary and $0.001 per job row. Companies without a public board on a supported provider cost nothing.
Questions agents ask
- “Is Notion hiring engineers? How many roles, where, and since when? Link the postings.”
Example
Input
{
"companies": ["stripe.com", "Notion", "https://jobs.lever.co/spotify"],
"departments": ["engineering"],
"postedSince": "30d",
"maxJobsPerCompany": 20
}Output
{
"schema_version": "1",
"row_type": "company_summary",
"company": "notion.so",
"found": true,
"provider": "ashby",
"board_token": "notion",
"board_url": "https://jobs.ashbyhq.com/notion",
"source_url": "https://api.ashbyhq.com/posting-api/job-board/notion",
"total_open_roles": 150,
"matching_roles": 16,
"filters": { "keywords": ["engineer"], "posted_since": "2026-09-06T00:00:00Z" },
"by_department": [
{ "name": "Engineering", "count": 8 },
{ "name": "Security", "count": 3 },
{ "name": "Sales", "count": 2 }
],
"by_location": [
{ "name": "San Francisco, California", "count": 11 },
{ "name": "Dublin, Ireland", "count": 2 },
{ "name": "Hyderabad, India", "count": 1 }
],
"by_country": [
{ "name": "United States", "count": 12 },
{ "name": "Ireland", "count": 2 },
{ "name": "India", "count": 1 }
],
"remote_share": 0.0,
"posted_last_30_days": 6,
"newest_posted_at": "2026-11-04T23:19:02Z",
"oldest_posted_at": "2026-09-08T20:54:37Z",
"top_titles": [
{ "title": "Security Engineer, Detection and Response", "count": 2 },
{ "title": "Forward Deployed Engineer, India", "count": 1 },
{ "title": "Security Engineer, Corporate Security", "count": 1 }
],
"trend": null,
"jobs_returned": 3,
"other_boards": [],
"not_found_reason": null,
"warnings": [],
"retrieved_at": "2026-11-05T21:42:10Z"
}What you get
| Field | Type | Meaning |
|---|---|---|
schema_version | string | Output schema version. |
row_type | string | company_summary (one per input company, found or not) or job (one per open role). |
company | string | The company as given in the input. |
found | boolean | null | Summary rows: true if a public job board was found. Not-found rows are free of charge. |
provider | string | null | Job board provider: greenhouse, lever, lever-eu (Lever's EU instance) or ashby. |
board_token | string | null | The company's board name at the provider, e.g. stripe. Pass it as provider:token for an exact lookup. |
board_url | string | null | Summary rows: the company's public job board page. |
source_url | string | null | Summary rows: the public API URL all counts were computed from. Job rows: the job's public posting page. |
total_open_roles | integer | null | Summary rows: all open roles on the board, before filters. |
matching_roles | integer | null | Summary rows: open roles matching departments, locations, keywords and postedSince. All counts below are over these. |
filters | object | null | Summary rows: the filters applied (lower-cased), null if none. |
by_department | array | Summary rows: top 15 departments as {name, count}, largest first. Roles without a department are not listed. |
by_location | array | Summary rows: top 15 primary locations as written by the company, as {name, count}. |
by_country | array | Summary rows: top 15 countries as {name, count}: ISO codes for Lever, country names for Ashby, empty for Greenhouse (no country field). |
remote_share | number | null | Summary rows: share of matching roles marked remote, 0-1. Greenhouse: roles whose location text says remote. null when no roles match. |
posted_last_30_days | integer | null | Summary rows: matching roles posted in the 30 days before retrieved_at. |
newest_posted_at | string | null | Summary rows: newest posting date among matching roles (ISO 8601 UTC). |
oldest_posted_at | string | null | Summary rows: oldest posting date among matching roles: how long the company has been hiring for its open roles. |
top_titles | array | Summary rows: the 10 most common job titles as {title, count}. |
trend | object | null | Summary rows with compareWithPrevious: {previous_retrieved_at, previous_total_open_roles, change, new_jobs, closed_jobs} versus the last such run. null on the first run or when off. |
jobs_returned | integer | null | Summary rows: job rows returned for this company (at most maxJobsPerCompany, newest first). |
other_boards | array | Summary rows: other boards found for the same name (usually old, smaller ones). The board with most open roles is used. |
not_found_reason | string | null | Summary rows: why no board was found, and how to fix it. null when found. |
warnings | array | Summary rows: caveats in plain words, e.g. a provider that could not be read or several providers with a board under the same name. |
job_id | string | null | Job rows: the provider's job posting ID. |
title | string | null | Job rows: job title as published. |
department | string | null | Job rows: department (Greenhouse: top-level department). |
team | string | null | Job rows: team or sub-department, null if none or the same as department. |
location | string | null | Job rows: primary location as written by the company. |
other_locations | array | Job rows: further locations of the same posting (Lever, Ashby). |
country | string | null | Job rows: country: ISO 3166 alpha-2 for Lever, country name for Ashby, null for Greenhouse. |
workplace_type | string | null | Job rows: remote, hybrid or on-site (Lever, Ashby); null when not stated or on Greenhouse. |
remote | boolean | null | Job rows: true if remote; false if hybrid or on-site; null when unknown. Greenhouse: true when the location text says remote, else null. |
employment_type | string | null | Job rows: as the provider gives it, e.g. FullTime, Intern (Ashby) or Permanent (Lever commitment). null on Greenhouse. |
posted_at | string | null | Job rows: ISO 8601 UTC. Greenhouse: first published; Lever: created; Ashby: last published. |
updated_at | string | null | Job rows: last update (Greenhouse only), ISO 8601 UTC. |
retrieved_at | string | When the board was read (ISO 8601 UTC). |
Use with AI agents (MCP)
Add this URL to your MCP client (Claude, Cursor, VS Code, ...) to load the Actor as a tool through the Apify hosted MCP server. It signs you in with OAuth or accepts Authorization: Bearer <APIFY_TOKEN>. It works once the Actor is live on the Apify Store.
https://mcp.apify.com?tools=bosco_labs/company-hiring-signals
For “Is Notion hiring engineers? How many roles, where, and since when? Link the postings.” the agent passes:
{ "companies": ["notion.so"], "keywords": ["engineer"], "maxJobsPerCompany": 10 }
stable snake_case fields, ISO 8601 UTC dates, counts as numbers, null for unknown, a source URL per row. One summary is about 2-4 KB; a 5-company summary-only run is under 20 KB. Typical time: 5-15 seconds for 5 companies (Lever asks for one request per second, so many Lever lookups take a little longer).
Or call the Apify API: POST https://api.apify.com/v2/acts/bosco_labs~company-hiring-signals/run-sync-get-dataset-items with the input as JSON body. Cost: $0.005 per company found plus $0.001 per job row.
Input fields
| Field | Type | Meaning |
|---|---|---|
companies | array (required) | Companies to check, 1-50: a name ("Notion"), a website domain ("stripe.com"), a job board URL ("https://jobs.lever.co/spotify", "https://job-boards.greenhouse.io/airbnb", "https://jobs.ashbyhq.com/ramp") or provider:token ("greenhouse:stripe", "lever:spotify", "lever-eu:<token>", "ashby:notion"). Names and domains are matched to likely board names on Greenhouse, Lever and Ashby; a board URL is exact. Required. |
departments | array | Only count and return roles whose department or team has a word starting with one of these, case-insensitive, e.g. ["engineering", "data"]. Department names are each company's own (Stripe uses "Tech" and team codes), so keywords on the title is often more reliable. Empty = all departments. |
locations | array | Only roles whose location text, other locations or country contains one of these as whole words, case-insensitive ("US" does not match "Australia"), e.g. ["London", "Germany", "remote"]. Lever gives ISO country codes ("GB"), Ashby country names; Greenhouse has the location text only. Empty = all locations. |
keywords | array | Only roles whose job title has a word starting with one of these, case-insensitive ("engineer" matches "Engineering", "ai" not "Retail"), e.g. ["engineer", "data scientist"]. Empty = all titles. |
postedSince | string | Only roles first published on or after this date: an ISO date ("2026-10-01") or a number of days back ("30d"). Greenhouse: first published; Lever: created; Ashby: last published. Empty = any date. |
maxJobsPerCompany | integer | Most job rows to return per company, newest first, e.g. 20. Default 50, maximum 1000; 0 = summary only. The summary always counts all matching roles, whatever this limit. Each job row is charged. |
summaryOnly | boolean | true = one summary row per company and no job rows (cheapest; answers "is X hiring and where?"). Default false. |
compareWithPrevious | boolean | true = add a trend (change in open roles, new and closed jobs) versus the last run that also had this on, and save this run's job IDs for next time in the key-value store "company-hiring-signals-history" in your account. The first run has no trend. Default false. |
Sources, licence and limits
Which companies are covered? Companies whose public job board runs on Greenhouse, Lever or Ashby: many tech and venture-backed companies (Stripe, Airbnb, Figma, Spotify, Palantir, Notion, Ramp, ...). Companies on Workday, SmartRecruiters, Workable, iCIMS, SuccessFactors or their own careers site are not covered and come back as found: false at no charge.
A name gave no board or the wrong one. Board names don't always match the company name. Open the company's careers page, follow a job link, and pass that URL (e.g. https://job-boards.greenhouse.io/airbnb) or greenhouse:airbnb.
Why is by_country empty, or remote null? Greenhouse has no country or workplace field: remote is true only when the location text says "remote", and country counts are empty. Lever gives ISO country codes (GB), Ashby country names (United Kingdom).
What do departments look like? Each company names its own. Some use broad names ("Engineering"), some internal codes (Stripe: "Tech" with teams like "8217 Risk Engineering"). For Greenhouse, department is the top-level department and team the one the job sits in. Filtering on title keywords is often more reliable across companies.
What does posted_at mean? Greenhouse: first published; Lever: when the posting was created; Ashby: when it was last published. Postings are as the company publishes them; the Actor doesn't check whether a role is really still open.
Are job descriptions or salaries included? No. Rows hold titles, departments, locations, dates and links; descriptions stay on the linked posting page.
Personal data? Company-level data only. No recruiter or hiring-manager names or emails are collected or output.
How fresh is it? Live: every run reads the job boards directly.