# Company Jobs Search: Live Career Site Jobs API (`enisbodlli/company-jobs-search`) Actor

Search open jobs by title on 1,302 company career sites, read live from Greenhouse, Lever, Ashby and Workday during the run. Filter by location, remote or hybrid, employment type, seniority, department, posting date and salary. One format for every source. Pay per job.

- **URL**: https://apify.com/enisbodlli/company-jobs-search.md
- **Developed by:** [Enis Bodlli](https://apify.com/enisbodlli) (community)
- **Categories:** Jobs, Lead generation, Agents
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.00 / 1,000 jobs

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

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

## Company Jobs Search: Live Career Site Jobs API

Search **open jobs by job title on 1,302 company career sites in one run**. Every run reads the
companies' own job boards on **Greenhouse, Lever, Ashby and Workday** at that moment, so there is no
stored database between you and the employer: a job posted an hour ago is found and a job closed
this morning is gone. It is built for job boards and newsletters, recruiters and sales teams looking
for companies that are hiring, analysts who follow a job market, and AI agents that need current
postings in one fixed format.

- **One search across many employers.** No company list to prepare: the Actor ships with 1,302 job
  boards, and you can add your own.
- **Filters that are kept on every row.** Title, location, remote or hybrid, employment type,
  seniority, department, posting date and salary. A job is saved only when it passes every filter you
  set, as it is saved.
- **Pay per job, from $2.00 per 1,000.** Every row carries `scrapedAt`, a time inside your run, and
  `jobUrl`, the employer's own posting.

The easiest way to try it: keep the example input and press **Start**. You get 50 software engineer
jobs from several companies in under a minute.

### What one job looks like

```json
{
    "company": "airwallex",
    "ats": "ashby",
    "title": "Senior Software Engineer, AI Tooling",
    "seniority": "senior",
    "department": "Engineering",
    "location": "US - San Francisco",
    "workplaceType": "hybrid",
    "employmentType": "full_time",
    "salaryMin": 200000,
    "salaryMax": 250000,
    "salaryCurrency": "USD",
    "salaryInterval": "year",
    "publishedAt": "2025-11-02T22:49:59.311Z",
    "jobUrl": "https://jobs.ashbyhq.com/airwallex/d943812b-edf6-4f92-bce3-1bbab2d8a480",
    "scrapedAt": "2026-10-07T22:02:45.125Z"
}
```

These are 15 of the 27 fields of a row; the full rows are under [Output](#output) below.

### What you can do with it

- **Fill a niche job board or newsletter**, for example remote data engineering jobs or product
  manager jobs in Berlin, with postings taken from the employers themselves.
- **Find companies that are hiring for a role**, as leads for recruiting, staffing or sales. A company
  with five open "account executive" postings is building a sales team.
- **Watch a job market over time.** Schedule a daily run with *Posted within the last days* set to 1
  and collect each day's new postings for a title.
- **Compare stated pay** for a role across companies with *Only jobs with a salary* or *Minimum
  yearly salary*.
- **Give an AI agent or a spreadsheet** current job postings to work with, in one fixed format.

### How to use it

1. Under **Job title keywords**, add one or more words or phrases, for example `software engineer`
   or `product manager`. A job matches when its title contains at least one of them.
2. Narrow it down if you want: **Locations** and **Exclude locations**, **Remote jobs only** or
   **Workplace types**, **Employment types**, **Seniority**, **Departments**, **Exclude title
   keywords**, **Posted within the last days**, **Only jobs with a salary** or **Minimum yearly
   salary**. Filters combine: a job must pass all the ones you set.
3. To search some companies only, list them under **Only these companies**. To leave some out, use
   **Exclude companies**. To add a company the built-in list lacks, use **Extra companies**.
4. Set **Maximum jobs**, and **Maximum jobs per company** if one large employer should not fill the
   result. The run stops as soon as the maximum is saved.
5. Press **Start**, then export the results as JSON, CSV or Excel, or read them through the API.

The largest companies are searched first, so a common title fills up within seconds. A rare title
makes the Actor go through every company, which takes 4 to 5 minutes.

### Pricing

You pay per job saved to the dataset, plus $0.00005 per run start. Platform usage is included, so
there is nothing else to pay.

| Apify plan tier | Price per 1,000 jobs | Price per job |
|---|---|---|
| Free, Bronze | $3.00 | $0.003 |
| Silver | $2.50 | $0.0025 |
| Gold and above | $2.00 | $0.002 |

Worked examples at the Free and Bronze price:

- The example input, 50 software engineer jobs: 50 x $0.003 = **$0.15**.
- 200 jobs, the default maximum: $0.60.
- 1,000 jobs: $3.00, or $2.50 on Silver and $2.00 on Gold.
- A daily run that returns 30 new postings: $0.09 a day, about $2.70 a month.
- A search that finds nothing: $0.00005, the run start.

**Maximum jobs** caps what one run can cost. You can also set a maximum charge per run: the Actor
then saves only as many jobs as that amount pays for, starts no further company and ends as
succeeded with a message that says the limit stopped it.

You are charged only for jobs that are saved. A run that fails or is stopped halfway costs what it
had saved until then. A run that Apify restarts on another server carries on where it stopped: it
asks the dataset which jobs are already saved and saves none of them twice.

### Input

| Field | What it does |
|---|---|
| Job title keywords (`keywords`) | Words or phrases to look for in the job title. A job matches when its title contains any of them. Not case sensitive. Required. |
| Exclude title keywords (`excludeKeywords`) | Leave out jobs whose title contains any of these. |
| Locations (`locations`) | Keep jobs whose location contains any of these texts, as the employer wrote the location. |
| Exclude locations (`excludeLocations`) | Leave out a job when any of its listed locations contains one of these texts. |
| Remote jobs only (`remoteOnly`) | Keep only jobs marked as remote. |
| Workplace types (`workplaceTypes`) | Keep only `remote`, `hybrid` or `onsite` jobs. A job whose board states no workplace type is left out. |
| Employment types (`employmentTypes`) | Keep only `full_time`, `part_time`, `contract`, `temporary` or `internship`. A job whose type the job system does not state is kept. |
| Seniority (`seniority`) | Keep only these ranks: `intern`, `entry`, `mid`, `senior`, `lead`, `staff`, `principal`, `manager`, `director`, `vp`, `executive`. Read from the job title. |
| Departments (`departments`) | Keep jobs whose department or team contains any of these words, as the employer names them. A job in no department is left out. |
| Posted within the last days (`postedWithinDays`) | Keep jobs published in the last N days. 0 keeps every date. |
| Only jobs with a salary (`hasSalary`) | Keep only jobs that state pay. |
| Minimum yearly salary (`minSalary`) | Keep jobs whose stated yearly pay reaches this amount at the top of its range. |
| Only these companies (`companies`) | Search these companies instead of the whole built-in list. |
| Exclude companies (`excludeCompanies`) | Skip these companies. |
| Job board systems (`systems`) | Search only companies on `greenhouse`, `lever`, `ashby` or `workday`. Empty searches all four. |
| Extra companies (`extraCompanies`) | Job board addresses or board names to search in addition to the built-in list. |
| Include job description (`includeDescription`) | Add the description as plain text and HTML. Default: off. |
| Maximum jobs per company (`maxJobsPerCompany`) | Take at most this many jobs from one company. 0 means no limit. |
| Maximum jobs (`maxResults`) | Stop as soon as this many jobs are saved. Default: 200. |

Example: senior data jobs in London or remote, posted in the last two weeks, full time, at most five
per company.

```json
{
    "keywords": ["data engineer", "analytics engineer"],
    "excludeKeywords": ["intern"],
    "locations": ["london", "remote"],
    "excludeLocations": ["india"],
    "employmentTypes": ["full_time"],
    "seniority": ["senior", "staff"],
    "postedWithinDays": 14,
    "extraCompanies": ["https://jobs.ashbyhq.com/linear"],
    "maxJobsPerCompany": 5,
    "maxResults": 100
}
```

### Output

One item per job posting, 27 fields, every field on every row. A field is `null` when the job board
does not provide it. These rows are from runs on 7 October 2026:

```json
[
    {
        "company": "airwallex",
        "companyName": null,
        "ats": "ashby",
        "jobId": "d943812b-edf6-4f92-bce3-1bbab2d8a480",
        "title": "Senior Software Engineer, AI Tooling",
        "seniority": "senior",
        "department": "Engineering",
        "team": "Information Security",
        "location": "US - San Francisco",
        "locations": ["US - San Francisco"],
        "isRemote": true,
        "workplaceType": "hybrid",
        "employmentType": "full_time",
        "employmentTypeText": "FullTime",
        "salaryMin": 200000,
        "salaryMax": 250000,
        "salaryCurrency": "USD",
        "salaryInterval": "year",
        "salaryText": "$200K - $250K",
        "salarySource": "ats",
        "publishedAt": "2025-11-02T22:49:59.311Z",
        "updatedAt": null,
        "jobUrl": "https://jobs.ashbyhq.com/airwallex/d943812b-edf6-4f92-bce3-1bbab2d8a480",
        "applyUrl": "https://jobs.ashbyhq.com/airwallex/d943812b-edf6-4f92-bce3-1bbab2d8a480/application",
        "descriptionText": null,
        "descriptionHtml": null,
        "scrapedAt": "2026-10-07T22:02:45.125Z"
    },
    {
        "company": "spacex",
        "companyName": "SpaceX",
        "ats": "greenhouse",
        "jobId": "8782397002",
        "title": "AI Security Software Engineer (Starshield)",
        "seniority": null,
        "department": null,
        "team": null,
        "location": "Hawthorne, CA",
        "locations": ["Hawthorne, CA"],
        "isRemote": null,
        "workplaceType": null,
        "employmentType": null,
        "employmentTypeText": null,
        "salaryMin": null,
        "salaryMax": null,
        "salaryCurrency": null,
        "salaryInterval": null,
        "salaryText": null,
        "salarySource": null,
        "publishedAt": "2026-09-03T23:14:16.000Z",
        "updatedAt": "2026-09-29T21:52:51.000Z",
        "jobUrl": "https://boards.greenhouse.io/spacex/jobs/8782397002?gh_jid=8782397002",
        "applyUrl": "https://boards.greenhouse.io/spacex/jobs/8782397002?gh_jid=8782397002",
        "descriptionText": null,
        "descriptionHtml": null,
        "scrapedAt": "2026-10-07T22:02:40.758Z"
    },
    {
        "company": "prima",
        "companyName": null,
        "ats": "lever",
        "jobId": "1211d8cc-cda2-4a65-9743-cab60f83a8b1",
        "title": "Senior Data Engineer",
        "seniority": "senior",
        "department": "Engineering",
        "team": "Engineering",
        "location": "Milan",
        "locations": ["Milan"],
        "isRemote": true,
        "workplaceType": "remote",
        "employmentType": "full_time",
        "employmentTypeText": "Permanent Employment",
        "salaryMin": 55000,
        "salaryMax": 85000,
        "salaryCurrency": "EUR",
        "salaryInterval": "year",
        "salaryText": null,
        "salarySource": "ats",
        "publishedAt": "2025-05-23T08:49:04.089Z",
        "updatedAt": null,
        "jobUrl": "https://jobs.eu.lever.co/prima/1211d8cc-cda2-4a65-9743-cab60f83a8b1",
        "applyUrl": "https://jobs.eu.lever.co/prima/1211d8cc-cda2-4a65-9743-cab60f83a8b1/apply",
        "descriptionText": null,
        "descriptionHtml": null,
        "scrapedAt": "2026-10-07T22:15:37.522Z"
    }
]
```

| Field | What it holds |
|---|---|
| `company`, `ats`, `jobId` | The name of the company's job board, the job system (`greenhouse`, `lever`, `ashby`, `workday`) and the posting's ID. Together they identify a posting; no two rows of a run share all three. |
| `companyName` | The company's display name. Filled for the 723 Greenhouse boards; `null` on Lever, Ashby and Workday, where the board gives none. |
| `title` | The job title as the employer wrote it. |
| `seniority` | The rank the title states, read by fixed rules: "Senior Software Engineer" is `senior`, "Engineering Manager" is `manager`, "Product Manager" states no rank and is `null`. Nothing is guessed. |
| `department`, `team` | As the employer names them. Workday gives neither. For a Greenhouse job `department` is filled when the *Departments* filter is set or *Include job description* is on, and `team` is always `null`. |
| `location`, `locations` | The primary location and every listed one, as the employer wrote them. For a Greenhouse job `locations` holds the primary location only. |
| `isRemote`, `workplaceType` | The remote flag and `remote`, `hybrid` or `onsite`, where the board states them. |
| `employmentType`, `employmentTypeText` | The type in one vocabulary (`full_time`, `part_time`, `contract`, `temporary`, `internship`) and exactly as the job system writes it. |
| `salaryMin`, `salaryMax`, `salaryCurrency`, `salaryInterval`, `salaryText` | The stated pay range, its three-letter currency, its period (`year`, `month`, `week`, `day`, `hour`) and the pay as the posting words it. |
| `salarySource` | `ats` when the job system publishes the pay in its own fields (Lever, Ashby, and the pay ranges some companies publish on Greenhouse), `description` when the range was read from the description text, `null` when no pay is stated. |
| `publishedAt`, `updatedAt` | ISO 8601 in UTC. `updatedAt` is Greenhouse only. |
| `jobUrl`, `applyUrl` | The posting on the employer's own career site or job board, and its application page. |
| `descriptionText`, `descriptionHtml` | The full description when *Include job description* is on, otherwise `null`. Cut at 200,000 characters. |
| `scrapedAt` | When the job board was read for this posting. Always inside the run. |

Every run also writes a `RUN_SUMMARY` record to its key-value store: how many jobs were saved, how
many companies were searched, which were skipped or searched only in part and why, which input
entries could not be used, and why the run stopped.

### Which companies are covered

The built-in list holds **1,302 company job boards** that had at least one open job when the list
was checked on 4 October 2026: **723 on Greenhouse, 200 on Lever, 374 on Ashby** and **5 Workday
careers sites** (NVIDIA, Salesforce, Mastercard, Intel and Adobe). Together they listed about 68,000
open jobs that day. Many are technology companies, from startups to large employers.

The list was built from openly licensed company lists, and each board was confirmed on its job
board system. It is refreshed with new versions of the Actor.

**Add your own companies** under *Extra companies*. Use the job board address
(`https://boards.greenhouse.io/stripe`, `https://jobs.lever.co/palantir`,
`https://jobs.ashbyhq.com/openai`, `https://nvidia.wd5.myworkdayjobs.com/NVIDIAExternalCareerSite`)
or, for Greenhouse, Lever and Ashby, just the board name (`stripe`). A Workday company always needs
the address. The companies you name are searched first, and one that is already in the list is
searched once.

### Limits

What the Actor does not do, in plain words.

**Coverage**

- **It searches the companies in its list, not the whole job market.** 1,302 job boards on
  Greenhouse, Lever, Ashby and Workday (checked 4 October 2026), plus the ones you add under *Extra
  companies*. Other job systems, such as SmartRecruiters or Workable, are not read.
- **Nothing is stored between runs.** There is no history of past postings, no feed of expired jobs
  and no expiry date: the boards publish no end date, and a closed job is simply not returned.
- **No contact data about people.** There are no fields for a recruiter's or hiring manager's name,
  email or phone, and the Actor extracts none. A job description is the employer's published advert
  and is returned as written when *Include job description* is on, so a name or address the employer
  wrote into the advert stays in that text.
- **No company profile.** No logo, website, headcount, industry or funding. `companyName` is filled
  for the 723 Greenhouse boards and is `null` on Lever, Ashby and Workday.

**Filters that do not exist**

- **No country, region or city as separate, normalised values.** The boards publish a location as
  free text, and *Locations* is compared with that text: `United States` does not find a job listed
  as `San Francisco, CA`. Add the wordings you expect.
- **No search inside the job description.** Keywords are compared with the job title only.
- **No time window shorter than one day.** Workday publishes no time of day, and a pass over every
  board takes 4 to 5 minutes. The smallest window is *Posted within the last days* set to 1.
- **No posted-before filter.** Every row carries `publishedAt`; filter on it after the run.
- **No filter by company website domain.** The list holds a company's job board, not its website.
- **No industry or company-size filter**, and **no removal of staffing-agency postings.** Both need
  facts about a company that its job board does not publish.
- **No fields read by a language model**: no skills, benefits, visa sponsorship, language, years of
  experience or summary of requirements. Seniority, employment type and salary are read by fixed
  rules instead, so the same posting always gives the same values.
- **No only-new-since-the-last-run switch, radius search, currency conversion, notifications,
  Markdown description or sort order.** For new postings, schedule a run with *Posted within the
  last days* set to 1, or use ATS Job Postings (below), which returns only what appeared since the
  previous run.

**How the filters behave**

- Results come in the order the job boards answer, not sorted by date. Sort by `publishedAt` after
  the run if you need the newest first.
- When **Maximum jobs** is reached the run stops, so the result is the first matches found, not a
  sample of all of them. Raise the maximum to get all.
- *Workplace types* leaves out a job whose board states none. Lever and Ashby state it for most
  jobs. Greenhouse has no such field: a Greenhouse job counts as remote when its location text
  contains the word remote, and has no workplace type otherwise.
- *Employment types* keeps a job whose type the job system does not state, because Greenhouse
  states none.
- *Seniority* leaves out a title without a rank word, such as "Software Engineer".
- *Departments* compares the employer's own names, and leaves out a job that sits in no
  department. Workday lists no department, so its jobs do not pass this filter. Greenhouse names a
  job's department in a list of its own, which the Actor reads for every company that has a job
  passing your other filters: one more request for such a company.
- On Greenhouse the job list carries neither department nor offices. A Greenhouse row therefore
  has `department` filled only when the *Departments* filter is set or *Include job description* is
  on, and its `locations` holds the primary location only.
- *Only jobs with a salary* and *Minimum yearly salary* read the pay the job system publishes in its
  own fields (Lever, Ashby, and the pay ranges some companies publish on Greenhouse) and, on Lever,
  Ashby and Workday, a pay range written in the description. On Greenhouse a figure that appears
  only in the description text is not used by these two filters. Workday states pay only in the
  description of the posting, so the Actor opens a Workday posting to read it when one of these
  filters is set.
- *Minimum yearly salary* compares the number as stated, without converting currencies, and leaves
  out hourly, daily, weekly and monthly pay.
- *Posted within the last days* leaves out a job without a published date. Workday shows a rough
  date ("posted 3 days ago") that the Actor turns into a day, and no date for postings older than
  30 days.

**Requests and caps**

- The Actor sends at most **4 requests a second to one job board host**, and at most **1 request a
  second to Lever**, whose `robots.txt` asks for a crawl delay of one second. That is why a search
  through every company takes 4 to 5 minutes (271 seconds when measured on 7 October 2026). No
  browser and no proxy are used.
- A refusal is final. A job board host that refuses three requests in a row (HTTP 403, HTTP 429, or
  a page where data belongs) is not asked again in that run; its remaining companies are counted as
  skipped, and `RUN_SUMMARY` names the host and the reason. Nothing is done to get around a block.
- A job board that does not answer, or that a company has closed since the list was built, is
  skipped. The status message and `RUN_SUMMARY` say how many were searched and skipped.
- Workday lists at most 2,000 postings per careers site; a site that reaches that number is named in
  `RUN_SUMMARY`. A Workday list shows the title, a rough date and one place or a count of places;
  every place, the employment type and the pay are on the posting itself. The Actor opens a posting
  only when a filter needs one of those or the description is wanted, and stops after 200 postings
  of one site that did not pass. `RUN_SUMMARY` then names the site as searched in part.
- An address under *Extra companies* must be a job board address. A careers page on the company's
  own website is not read; open a job on it and paste the address you land on.
- With *Include job description* on, the description is fetched only for the jobs that are saved:
  one more request for a small board (up to 300 postings on Greenhouse, under 100 on Lever, any
  Ashby board), one request per saved job for a larger one.
  A run with descriptions therefore takes longer than one without: a pass over every company that
  saved one job from each took about 8 minutes on 7 October 2026, against 4 to 5 without.
- A description longer than 200,000 characters is cut at that length.

### FAQ

**Is it legal to scrape job postings from company career sites?**
The Actor reads public job postings without a login: through the endpoints Greenhouse, Lever and
Ashby offer for showing a company's jobs on other sites, and through the public endpoint a Workday
careers site itself calls to list its jobs. It keeps to the pace Lever's `robots.txt` asks for,
stops at a refusal and puts no person's name, email or phone into a field. Some site terms restrict
automated access: Workday's site terms, as read on 7 October 2026, prohibit data mining, robots and
similar extraction methods on Workday's sites. You are responsible for how you use the results. This
is not legal advice.

**How fresh are the results?**
As fresh as the company's own careers page. Every run reads the job boards at that moment; nothing
is stored between runs. `scrapedAt` on each row is the time of that read.

**A company I care about is missing. What can I do?**
Add it under *Extra companies*. Open the company's careers page and click a job: if the address
contains `greenhouse.io`, `lever.co`, `ashbyhq.com` or `myworkdayjobs.com`, paste that address.

**Why did I get fewer jobs than the maximum?**
Every company was searched and that is all that matched. Try a shorter keyword (`engineer` instead
of `senior software engineer`), add more keywords, or remove a filter.

**Why did my search return nothing?**
No job title on the searched boards contained your keyword with the filters you set. The run ends
as succeeded with an empty dataset and a status message that says so. Check the spelling, try a more
common title, and remember that *Locations* matches the employer's wording.

**Why did my run fail?**
A run ends as failed, with the reason in its status message, when the input cannot be used (for
example no keyword, or no company left to search), when more companies could not be read than
could, when nothing was found while a job board host was refusing requests, or when the Actor itself
could not process a company's answer or save its jobs. In those cases "no more jobs" would not be a
true answer, so the run does not claim it. Jobs saved before the failure stay in the dataset, and
only those are charged. `RUN_SUMMARY` names the companies concerned.

**Can I get only new jobs every day?**
Schedule the Actor and set *Posted within the last days* to 1. To follow chosen companies and get
only postings that appeared since the previous run, use ATS Job Postings (below).

**Something broke or a field is missing.**
Open an issue on the Issues tab with the input you ran.

### More Actors from this developer

Job postings:

- [ATS Job Postings: Workday, Greenhouse, Lever & Ashby](https://apify.com/enisbodlli/ats-job-postings):
  every open job of the companies you choose, with full descriptions, and optionally only the
  postings that are new since the last run. Use it when you already know which companies you want.
- [Workday Jobs Scraper](https://apify.com/enisbodlli/workday-jobs-scraper),
  [Greenhouse Jobs Scraper](https://apify.com/enisbodlli/greenhouse-jobs-scraper),
  [Lever Jobs Scraper](https://apify.com/enisbodlli/lever-jobs-scraper) and
  [Ashby Jobs Scraper](https://apify.com/enisbodlli/ashby-jobs-scraper): the same for one job system.

Company data from official registers:

- [North Data Scraper: German & European Companies](https://apify.com/enisbodlli/northdata-company-scraper)
- [Handelsregister Scraper: German Company Register](https://apify.com/enisbodlli/handelsregister-scraper)
- [Brazil CNPJ Scraper: Company Search & Lookup](https://apify.com/enisbodlli/brazil-cnpj-company-search)
- [US Business Entity Search & New Business Filings](https://apify.com/enisbodlli/us-business-registry-search)
- [European Company Registry Search: 8 Registers](https://apify.com/enisbodlli/eu-company-registry-search)

Contact data:

- [Website Contact Scraper](https://apify.com/enisbodlli/website-contact-scraper): emails, phone
  numbers and social profiles from company websites.
- [Email Validator & List Cleaner](https://apify.com/enisbodlli/email-validator): clean an email
  list before a campaign.

# Changelog

This Actor's version history is a separate document: https://apify.com/enisbodlli/company-jobs-search/changelog.md

# Actor input Schema

## `keywords` (type: `array`):

Words or phrases to look for in the job title, for example software engineer or product manager. A job matches when its title contains at least one of them. Not case sensitive. Required.

## `excludeKeywords` (type: `array`):

Leave out jobs whose title contains any of these words or phrases, for example intern or manager. Not case sensitive.

## `locations` (type: `array`):

Keep only jobs whose location contains at least one of these words or phrases, for example Berlin, United Kingdom or Remote. Not case sensitive. The text is compared with the location as the employer wrote it: United States does not find a job listed as San Francisco, CA, so add the wordings you expect. Leave empty to keep every location.

## `excludeLocations` (type: `array`):

Leave out a job when any of its listed locations contains one of these words or phrases, for example India or Remote. Not case sensitive. A job that lists no location is kept.

## `remoteOnly` (type: `boolean`):

Keep only jobs marked as remote. Greenhouse has no remote flag, so a Greenhouse job counts as remote when its location text contains the word remote.

## `workplaceTypes` (type: `array`):

Keep only jobs with one of these work arrangements. A job whose board states none is left out: Lever and Ashby state it for most jobs, Greenhouse states none (a Greenhouse job passes only as remote, when its location text says remote), and Workday only where the job list itself shows it. Leave empty to keep every job.

## `employmentTypes` (type: `array`):

Keep only jobs of these types. A job whose type the job system does not state is kept, because Greenhouse states none.

## `seniority` (type: `array`):

Keep only jobs whose title states one of these ranks. The rank is read from the job title by fixed rules: Senior Software Engineer is senior, Engineering Manager is manager. A title without a rank word, such as Software Engineer, has no seniority and is left out when this filter is set. Leave empty to keep every job.

## `departments` (type: `array`):

Keep only jobs whose department or team contains at least one of these words, for example engineering or sales. Not case sensitive. Departments are compared as each employer names them; there is no common list of job categories. A job that sits in no department is left out. Workday lists no department, so its jobs do not pass this filter.

## `postedWithinDays` (type: `integer`):

Keep only jobs published in the last this many days, for example 7 for the past week. 0 keeps every date. Jobs without a published date are left out when this is set. The smallest window is 1 day.

## `hasSalary` (type: `boolean`):

Keep only jobs that state pay: in the job system's own salary fields (Lever, Ashby and the pay ranges some companies publish on Greenhouse), or, on Lever, Ashby and Workday, as a pay range written in the description. On Greenhouse a figure that appears only in the description text is not used by this filter.

## `minSalary` (type: `integer`):

Keep only jobs whose stated yearly pay reaches at least this amount at the top of its range, for example 120000. The number is compared as stated, in the employer's currency, without conversion. Jobs with hourly, daily, weekly or monthly pay, and jobs that state no pay, are left out. 0 turns this off.

## `companies` (type: `array`):

Search only these companies instead of the whole built-in list. Use the company or board name (for example stripe or Scale AI) or a job board address. A name that is not in the built-in list is looked up on Greenhouse, Lever and Ashby. Leave empty to search every company.

## `excludeCompanies` (type: `array`):

Skip these companies. Use the value of the company field of a result (for example stripe) or the company name.

## `systems` (type: `array`):

Search only the companies of the built-in list whose career site runs on these systems. Leave empty to search all four. Companies you name yourself are searched whatever their system.

## `extraCompanies` (type: `array`):

Companies to search in addition to the built-in list. Use the job board address (for example https://boards.greenhouse.io/stripe, https://jobs.lever.co/palantir, https://jobs.ashbyhq.com/openai or https://nvidia.wd5.myworkdayjobs.com/NVIDIAExternalCareerSite) or a board name (for example stripe). Workday always needs the address. A company that is already in the list is searched once.

## `includeDescription` (type: `boolean`):

Add the full job description as plain text and as HTML. Off by default for smaller, faster results.

## `maxJobsPerCompany` (type: `integer`):

Take at most this many matching jobs from one company, so that a common job title is not filled by the first large company that answers. 0 means no limit.

## `maxResults` (type: `integer`):

Stop as soon as this many jobs are saved. You pay per saved job, so this is also the most one run can cost. The largest companies are searched first, so a common job title fills up within seconds.

## Actor input object example

```json
{
  "keywords": [
    "data engineer",
    "analytics engineer"
  ],
  "excludeKeywords": [
    "intern",
    "manager"
  ],
  "locations": [
    "London",
    "United Kingdom",
    "Remote"
  ],
  "excludeLocations": [
    "India",
    "Philippines"
  ],
  "remoteOnly": true,
  "workplaceTypes": [
    "remote",
    "hybrid"
  ],
  "employmentTypes": [
    "full_time"
  ],
  "seniority": [
    "senior",
    "staff"
  ],
  "departments": [
    "engineering",
    "data"
  ],
  "postedWithinDays": 7,
  "hasSalary": true,
  "minSalary": 120000,
  "companies": [
    "stripe",
    "databricks",
    "Scale AI"
  ],
  "excludeCompanies": [
    "spacex"
  ],
  "systems": [
    "greenhouse",
    "ashby"
  ],
  "extraCompanies": [
    "https://jobs.ashbyhq.com/linear",
    "https://jobs.lever.co/palantir"
  ],
  "includeDescription": true,
  "maxJobsPerCompany": 5,
  "maxResults": 100
}
```

# Actor output Schema

## `results` (type: `string`):

One item per job posting that passed every filter, in the run's default dataset: company, title, location, workplace and employment type, seniority, salary, dates and the links to the posting and its application page.

## `runSummary` (type: `string`):

What the run did: how many jobs were saved, how many companies were searched, which were skipped or searched only in part and why, and why the run stopped.

# 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 = {
    "keywords": [
        "software engineer"
    ],
    "maxJobsPerCompany": 10,
    "maxResults": 50
};

// Run the Actor and wait for it to finish
const run = await client.actor("enisbodlli/company-jobs-search").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 = {
    "keywords": ["software engineer"],
    "maxJobsPerCompany": 10,
    "maxResults": 50,
}

# Run the Actor and wait for it to finish
run = client.actor("enisbodlli/company-jobs-search").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 '{
  "keywords": [
    "software engineer"
  ],
  "maxJobsPerCompany": 10,
  "maxResults": 50
}' |
apify call enisbodlli/company-jobs-search --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,enisbodlli/company-jobs-search"
        }
    }
}
```

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/0F0rk68MR5UJDnaKY/builds/lt6S8AdYSH2mWjCBi/openapi.json
