# LinkedIn Jobs Database API — Advanced Search + Decision Makers (`b2bsearch/linkedin-job-search-api`) Actor

Search 50M+ LinkedIn job postings with database-grade filters: boolean title and description search, exclusions, employer size, industry, seniority, salary, applicants, expired jobs. Each job: full text, company card, recruiter; add the employer's hiring pace and decision makers. $0.80/1,000.

- **URL**: https://apify.com/b2bsearch/linkedin-job-search-api.md
- **Developed by:** [B2B Enrich Search](https://apify.com/b2bsearch) (community)
- **Categories:** Jobs, Lead generation, AI
- **Stats:** 1 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: 5.00 out of 5 stars

## Pricing

from $0.80 / 1,000 job delivereds

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

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

### What does LinkedIn Jobs Database API do?

**LinkedIn Jobs Database API** is a search over our database of **50M+ LinkedIn job postings from the last 180 days**, with the filters a database can apply exactly and two things a plain job feed cannot give you: a **free breakdown of the market** before you buy a single row, and the **people behind each posting**: the recruiter named on it, the employer's hiring pace, and the employer's decision makers.

One Actor, three jobs:

1. **Search jobs with database-grade filters.** Title and description search with boolean operators and exclusions, locations with exclusions, exact employers and employer size, industry, seniority, employment type, salary as a number in a currency, applicant count, years of experience required, recruiter-only, posting window, and expired postings as a filter rather than a second product. Up to 10,000 jobs per run, newest first, each job once.
2. **Measure the market, free.** `previewOnly` returns how many postings match and their split by country, seniority, employment type, industry, top employers, titles and cities. No charge.
3. **Reach the people who hire.** Every row carries the recruiter card when the posting names one. `employerHiring` adds the employer's open roles and posting pace. `decisionMakers` adds the founders, C-level, VPs and directors of each hiring employer as rows of their own, with the email on record when the contact tier is on.

**$0.80 per 1,000 jobs**, company card and recruiter card included. **$3.20 per 1,000 decision makers.** Counts, misses and refused inputs are free. No cookies, no login, no API key of yours.

#### At a glance

| | |
|---|---|
| **What you get** | One row per job: title, description (text or HTML), location, posted date, seniority, employment type, salary, applicants, required experience, benefits, the company card (website, industry, headcount, country, funding), the recruiter card |
| **Search by** | Title and description (boolean, exclusions), location (country, US state, city; country exclusions), exact employers and employer name, employer size, industry (with exclusions), seniority, employment type, salary floor, applicant ceiling, years of experience, recruiter-only, posting window or date, status (active, expired, any) |
| **Price** | $0.80 per 1,000 jobs; company and recruiter cards included; counts and misses free |
| **Speed** | 1,000 jobs in about 30 seconds (measured 26 October 2026) |
| **Scale** | Up to 10,000 jobs per run; free Apify plan up to 100 |
| **People** | Recruiter card (free), the employer's hiring pace (free), the recruiter's full profile, the employer's decision makers with emails on record |
| **Feeds** | New postings with `timeRange: "24h"` on a schedule; closed postings with `status: "expired"` and `expiredAfter` |
| **Runs from** | Apify Console, REST API, schedules and webhooks, n8n, Make, Zapier, and MCP for AI agents |

#### How does it compare with the LinkedIn jobs database API on this Store?

Read from that Actor's Store page and README on 26 October 2026.

| | LinkedIn Jobs Database API (this Actor) | The jobs database API on this Store |
|---|---|---|
| Price per 1,000 jobs | $0.80 on every plan | $5.00 on the Free and Starter plans, $1.50 on Business |
| Recruiter on the row | Free card; the `recruiterOnly` filter is free | An extra per-row charge that triples the price of a row with a recruiter |
| Expired postings | A filter in the same run (`status`, `expiredAfter`) | A separate Actor at $20 a month |
| Count before you pay | Free, with the breakdown by country, seniority, type, industry, employer, title and city | None |
| Jobs per run | 10,000 | 5,000 |
| Locations | Country, US state or city by name or code (`UK`, `gb`, `London`) | Exact `City, State, Country` format, English names, no abbreviations |
| Seniority filter | Every country | English-speaking countries only |
| The employer's hiring pace on the row | Free | No |
| Decision makers of the employer | $3.20 per 1,000 people | No |
| Remote / hybrid, Easy Apply, visa sponsorship, AI-derived fields | Not in this database: refused, never faked | On technology roles |
| Freshness | Reloaded after each data update; every row carries `dataAsOf` | Indexed continuously, about an hour behind |

The last two rows are the honest part. If you need a remote flag or hourly freshness, that API is the better tool today. If you need exact filters, a count before you pay, the recruiter for free and the people to contact, this one is.

#### Who uses it, and how?

| If you are | You can | Start with |
|---|---|---|
| A job board or aggregator | Fill and refresh a board: new postings every day, closed ones removed by their `jobId` | `timeRange: "24h"` on a daily schedule; a second schedule with `status: "expired"`, `expiredAfter` |
| A recruiter or sourcing team | Find the roles your candidates fit, with the recruiter to write to, and skip agencies | `titleSearch`, `locationSearch`, `recruiterOnly: true`, `removeAgency: true` |
| A B2B sales team | Spot companies hiring for the problem you solve and get the decision makers in the same run | `titleSearch`, `organizationEmployeesGte`, `organizationEmployeesLte`, `removeAgency: true`, `decisionMakers: true` |
| A market or HR analyst | Size demand for a skill or a role by country and city, benchmark published salaries, follow a technology through the descriptions | `previewOnly: true` first; then `descriptionSearch` with `titleSearch` and `hasSalary: true` |
| A competitive-intelligence team | Watch competitors' hiring: roles, levels, locations, pace | `organizationSlugFilter`, `timeRange: "30d"`, `employerHiring: true` |
| An AI agent builder | Give an agent live job data through MCP, with a free count before any paid call | The AI agents section below |

### What data do you get for each job?

| Field | Example | Filled |
|---|---|---|
| `jobId`, `url` | `4012345678`, `https://www.linkedin.com/jobs/view/4012345678/` | always |
| `title` | `Senior Software Engineer, Payments` | always |
| `postedAt`, `validUntil`, `isOpen`, `closedAt` | `2026-10-15T09:30:00Z`, `true` | always; `validUntil` when stated, `closedAt` on expired postings |
| `companyName`, `companyDomain`, `companyIndustry`, `companyEmployeeCount`, `companyCountryCode`, `companyUrl` | `Example Corp`, `example.com`, `Software Development`, `1240`, `US` | the card is on 99% of postings |
| `company` | the full card: website, industry, headcount, HQ, founded, funding, description | same |
| `locationText`, `location` | `Austin, TX`; `{ countryCode, region, locality, postalCode, lat, lon }` | always; coordinates on 57% |
| `seniorityLevel`, `employmentTypeName` | `Mid-Senior level`, `Full-time` | as stated on the posting |
| `industries` | `[{ id: 4, name: "Software Development" }]` | 99% |
| `salaryText`, `salary` | `$150K/yr - $190K/yr`; `{ min, max, currency, period, annualMin, annualMax }` | 13% overall; 50% in the Netherlands, 41% in China |
| `applicants`, `applicantRange` | `48`, `25-50 applicants` | the count on 10%, the bucket on every posting |
| `requiredExperienceMonths`, `education`, `benefits` | `60`, `Bachelor degree`, `["Medical insurance"]` | experience on 22% |
| `description`, `descriptionHtml` | the posting text, plain and as HTML | when `descriptionType` asks for it |
| `recruiterName`, `recruiterHeadline`, `recruiterUrl`, `recruiter` | `Jane Doe`, `Technical Recruiter at Example Corp` | on the 11% of postings that name one (28% in India, 17% in the UK, 7% in the US) |
| `recruiterProfile` | the recruiter's full career profile | with `recruiter: "profile"`, where the profile is on record |
| `employerOpenJobs`, `employerJobs7d`, `employerJobs30d`, `employerJobs90d`, `employerLastPostedAt`, `employerTopTitles30d`, `employerHiring` | `42`, `6`, `19`, `41`, `2026-10-21T08:00:00Z`, `["Software Engineer", "Account Executive"]` | with `employerHiring: true`, where the employer has a signal on record |
| `_type`, `_status`, `_input` | `job`, `found`, the filters and `dataAsOf` | always |

Unknown facts are left out, never shipped as empty strings. Every row's `_input.dataAsOf` is the date of the newest posting in the database at the time of the run.

### How to search LinkedIn jobs through the API (3 steps)

1. Enter **title search** terms and a **location** (a country by name or code, a US state, a city), or **employer slugs**.
2. Narrow with description search, exclusions, employer size, industry, seniority, employment type, salary, applicants, experience and the time range. Set **Max jobs**, your spend cap. Press **Start**. To size the search first, tick **Preview only**: the count and the breakdown are free.
3. Export the dataset as JSON, CSV or Excel, or read it through the API. Schedule it with `timeRange: "24h"` for a daily feed, and with `status: "expired"` for the expiry feed.

A search needs a country or an employer slug: a title alone, a city alone or an employer *name* alone is not a search here.

#### How do I search job descriptions for a technology?

Put the role in `titleSearch` and the technology in `descriptionSearch`: `data engineer` in the title, `kubernetes` in the description, Germany, last 30 days. The texts are read for the postings the other filters leave, so a description search needs a narrow cut: an employer in `organizationSlugFilter`, or a country with a time range of at most 30 days. A wider cut is refused before anything is charged, with the number of postings it would have to read.

#### How do I build a daily feed of new and closed jobs?

Two schedules of the same Actor. The first runs with `timeRange: "24h"` (or `datePostedAfter` set to your last run) and gives you the new postings; upsert them by `jobId`. The second runs with `status: "expired"` and `expiredAfter` set to yesterday and gives you the postings that closed; remove them by `jobId`. Each closed posting carries `isOpen: false` and `closedAt`.

### How much does the job search API cost?

**$0.80 per 1,000 jobs delivered** ($0.0008 per job), plus the Actor start fee of $0.0002 per run.

| Row | Price |
|---|---|
| Job delivered (`_status: found`, `_type: job`) | $0.0008 |
| Company card and recruiter card on the row; the `recruiterOnly` filter | $0, included |
| The employer's hiring pace on the row (`employerHiring: true`) | $0, included |
| Recruiter's full profile (`recruiter: "profile"`), per job that carries one | $0.0032 |
| Decision maker of the employer (`decisionMakers: true`), per person | $0.0032 |
| Preview and breakdown rows (`previewOnly`) | $0 |
| Search that matches nothing, refused input, posting skipped by the employer-size bound | $0 |

`limit` is your spend cap: at the default of 100 a run costs at most $0.08 for the jobs. Prices are the same on every Apify plan.

### Input

The form has five sections: **Search**, **Employers**, **More filters**, **People behind the job** and **Output**. An agent or an API call sends the same field names as JSON:

```json
{
  "titleSearch": ["software engineer", "backend engineer"],
  "titleExclusionSearch": ["intern", "staff engineer"],
  "locationSearch": ["United States"],
  "limit": 500,
  "timeRange": "7d",
  "descriptionSearch": ["kubernetes"],
  "organizationSlugExclusionFilter": ["acme-staffing"],
  "organizationEmployeesGte": 51,
  "organizationEmployeesLte": 5000,
  "removeAgency": true,
  "industryFilter": ["Software Development"],
  "seniorityFilter": ["Mid-Senior level"],
  "employmentTypeFilter": ["FULL_TIME"],
  "status": "active",
  "recruiter": "card",
  "employerHiring": true,
  "descriptionType": "text"
}
```

**Search**

- `titleSearch`, `titleExclusionSearch`: words or phrases the title must (not) contain; whole words, any case; a line may use `AND`, `OR`, `NOT`, `"exact phrase"`, parentheses. Up to 10 each. Prefix matching (`soft:*`) is not available and is refused.
- `locationSearch`: countries by name or code (`United States`, `Germany`, `gb`, `UK`), US states (`California`), cities (`Berlin`, `Austin, Texas`). Any of them. `locationExclusionSearch` takes whole countries only.
- `limit`: jobs per run (default 100, `0` = up to 10,000). Free Apify plan: up to 100.
- `previewOnly`: the count and breakdown instead of the rows, free. `compact`: short rows for AI agents.
- `timeRange`: `24h`, `7d` (default), `30d`, `90d`, `6m` (everything, 180 days).
- `descriptionSearch`, `descriptionExclusionSearch`: the same over the posting text, for a narrow cut (see the FAQ). Up to 10 each.

**Employers**

- `organizationSlugFilter`, `organizationSlugExclusionFilter`: exact employers: the page slug (`tesla-motors`), a page URL, a website domain or a numeric id. Up to 100 each. An employer list alone is a complete search.
- `organizationSearch`: employer names, matched as part of the recorded name (`Google` matches Google Cloud); several companies share a name, so use `organizationSlugFilter` for an exact employer. `organizationExclusionSearch` is not available; exclude by slug.
- `organizationEmployeesGte`, `organizationEmployeesLte`, `organizationSizeFilter`: the employer's headcount on record; postings at employers outside the bounds, or with no headcount on record, are skipped free.
- `removeAgency`: drops postings by staffing firms and job-board aggregators (by the posting's industry, and by the employer's own card: its industry and what its description says it does), and by employers with far more postings than employees (at least 200 open, or 100 posted in the last 30 days, and more than two per employee).

**More filters**

- `seniorityFilter`: `Internship`, `Entry level`, `Associate`, `Mid-Senior level`, `Director`, `Executive`, `Not Applicable`.
- `employmentTypeFilter`: `FULL_TIME`, `PART_TIME`, `CONTRACTOR`, `TEMPORARY`, `INTERN`, `VOLUNTEER`, `OTHER` (`aiEmploymentTypeFilter` is accepted as the same field; `PER_DIEM` is not in this data).
- `industryFilter`, `industryExclusionFilter`: industry names (`Software Development`) or numeric ids; an industry covers its sub-industries. Up to 30 each.
- `hasSalary`, `salaryMin`, `salaryCurrency`: only postings that state a salary; at least this yearly amount, in the given currency (default USD).
- `maxApplicants`: `25` … `200`: the applicant bucket (25 wide) the posting is in or below.
- `aiExperienceLevelFilter`: `0-2`, `2-5`, `5-10`, `10+` years of required experience, as the posting states it; about one posting in five states one, the others never match. Adjacent ranges are joined.
- `recruiterOnly`: only postings that name the recruiter or hiring manager. Free.
- `datePostedAfter`: a date instead of the window; with both, the later bound wins.
- `status`: `active` (default), `expired`, `any`; `expiredAfter` narrows expired postings to those closed on or after a date.

**People behind the job**

- `recruiter`: `card` (default, free), `profile` ($3.20 per 1,000 jobs that carry one) or `none`.
- `employerHiring`: the employer's hiring signal on each row, free: `employerOpenJobs`, `employerJobs7d`, `employerJobs30d`, `employerJobs90d`, `employerLastPostedAt`, `employerTopTitles30d`.
- `decisionMakers`, `decisionMakerRoles`, `decisionMakersPerCompany`, `decisionMakerTitleKeywords`: the leadership add-on, see below.

**Output**

- `descriptionType`: `text` (default), `html`, `both`, `none`. Same price.

### Output

One row per job. The flat columns lead, then the job as recorded. Values below are made up:

```json
{
  "_status": "found",
  "_type": "job",
  "_input": { "filters": { "title": "(software engineer) NOT intern", "countries": ["us"], "posted_after": "2026-10-19T12:00:00Z" }, "dataAsOf": "2026-10-21" },
  "jobId": 4012345678,
  "title": "Senior Software Engineer, Payments",
  "url": "https://www.linkedin.com/jobs/view/4012345678/",
  "postedAt": "2026-10-15T09:30:00Z",
  "companyName": "Example Corp",
  "companyDomain": "example.com",
  "companyIndustry": "Software Development",
  "companyEmployeeCount": 1240,
  "companyCountryCode": "US",
  "locationText": "Austin, TX",
  "countryCode": "US",
  "seniorityLevel": "Mid-Senior level",
  "employmentTypeName": "Full-time",
  "salaryText": "$150K/yr - $190K/yr",
  "applicantRange": "25-50 applicants",
  "recruiterName": "Jane Doe",
  "recruiterUrl": "https://www.linkedin.com/in/jane-doe-example",
  "employerOpenJobs": 42,
  "employerJobs7d": 6,
  "employerJobs30d": 19,
  "employerJobs90d": 41,
  "employerLastPostedAt": "2026-10-21T08:00:00Z",
  "employerTopTitles30d": ["Software Engineer", "Account Executive"],
  "isOpen": true,
  "validUntil": "2026-11-14T09:30:00Z",
  "location": { "text": "Austin, TX", "countryCode": "US", "region": "TX", "locality": "Austin" },
  "seniority": { "id": 16, "name": "Mid-Senior level" },
  "employmentType": { "id": 1, "name": "Full-time" },
  "industries": [{ "id": 4, "name": "Software Development" }],
  "salary": { "min": 150000, "max": 190000, "currency": "USD", "period": "year", "text": "$150K/yr - $190K/yr" },
  "requiredExperienceMonths": 60,
  "description": "About the role…",
  "company": { "id": 123456, "name": "Example Corp", "domain": "example.com", "employeeCount": 1240, "industry": "Software Development", "countryCode": "US", "funding": { "hasFunding": true, "lastRoundType": "series_c" }, "hq": { "locality": "Austin, TX", "region": "TX" } },
  "recruiter": { "kind": "person", "slug": "jane-doe-example", "url": "https://www.linkedin.com/in/jane-doe-example", "fullName": "Jane Doe", "headline": "Technical Recruiter at Example Corp" },
  "employerHiring": { "openJobs": 42, "jobs7d": 6, "jobs30d": 19, "jobs90d": 41, "lastPostedAt": "2026-10-21T08:00:00Z", "seniorities30d": [{ "id": 16, "name": "Mid-Senior level", "count": 11 }], "countries30d": ["us"], "topTitles30d": ["Software Engineer", "Account Executive"], "asOf": "2026-10-22T00:00:00Z" }
}
```

The `employer…` columns are there when `employerHiring` is on. An expired posting carries `isOpen: false` and `closedAt`. Free rows say why they are not a result: `no_results`, `invalid` (an employer entry that could not be read), `input_problem` (a refused input, with the field named), `no_decision_makers`, `error` (nothing charged).

The **Output tab** has five views: *Overview*, *Company & recruiter*, *Employer hiring*, *Decision makers* and *Preview & breakdown*.

### Decision makers: from a job to the people who hire

Turn on `decisionMakers` and every employer in the result is followed by its decision makers, each as a row of its own (`_type: decision_maker`): founders and owners, C-level, VPs and directors, ranked founder + CEO first, assistants and "Office of the CEO" staff removed, each person once per run. Each row carries `fullName`, `jobTitle`, `seniority`, `headline`, `linkedinUrl`, `location`, `forJobId` and `forJobTitle`; the email that reaches the person today rides the row when one is on record and the contact tier is on.

- `decisionMakerRoles`: `founder`, `cxo`, `vp`, `director`; default all four.
- `decisionMakersPerCompany`: people per employer, in rank order (default 3, maximum 25).
- `decisionMakerTitleKeywords`: keep only titles containing any of these words (`sales`, `engineering`, `talent`). C-level acronyms (`cto`, `coo`, `cfo` …) match as whole words, so `cto` finds "Co-Founder & CTO" and not "Director".

$3.20 per 1,000 people delivered; an employer with nobody at the chosen roles is a free row. For the same list without the jobs, use [Companies Hiring Now](https://apify.com/b2bsearch/hiring-companies-finder).

### Use LinkedIn Jobs Database API with AI agents and MCP

This Actor works as a tool for AI agents. Add it to Claude, ChatGPT, Cursor or any other MCP client through the Apify MCP server:

```
https://mcp.apify.com?tools=b2bsearch/linkedin-job-search-api
```

The same Actor is a tool in LangChain, CrewAI and the OpenAI Agents SDK, and a step in n8n, Make and Zapier through the Apify integrations.

#### What an agent should know before calling it

- **When to pick it.** The user wants LinkedIn job postings with precise filters (keywords in the description, exclusions, employer size, industry, seniority, salary, applicants, experience), a count of the market, expired postings, or the people behind the postings (recruiter, hiring pace, decision makers). For a plain title-and-location scrape in the best-known scraper's field names, [Advanced LinkedIn Jobs Scraper](https://apify.com/b2bsearch/linkedin-jobs-scraper) does the same rows. For the list of companies hiring, [Companies Hiring Now](https://apify.com/b2bsearch/hiring-companies-finder).
- **Minimal input.** `titleSearch` (array) plus `locationSearch` (array with at least one country), or `organizationSlugFilter` (array). `limit` is the number of rows to buy; the default is 100.
- **Count first.** Send `previewOnly: true` to get the number of matches and their breakdown for free, then decide how many rows to buy.
- **Cost.** $0.0008 per `found` job row, $0.0032 per decision-maker row; rows with any other `_status` are free. Cap a call with `maxTotalChargeUsd` in the run options.
- **Read the rows.** `_status` is `found` for a job; `_type` is `job`, `decision_maker` or `preview`. A row that is not a result says why in `_status` and `_error`. The useful columns are flat: `title`, `companyName`, `companyDomain`, `companyEmployeeCount`, `locationText`, `postedAt`, `seniorityLevel`, `employmentTypeName`, `salaryText`, `applicantRange`, `recruiterName`, `recruiterUrl`, `employerOpenJobs`, `url`.
- **Small rows.** `compact: true` keeps every plain column and cuts the description to 300 characters. `descriptionType: "none"` drops it.
- **Refusals are exact.** A field this database cannot answer (remote, Easy Apply, visa, language) stops the run before any charge and names the field. Do not retry with the same field.
- **Fast.** A small request finishes in seconds, inside one tool call.

Input an agent can send as is:

```json
{
  "titleSearch": ["software engineer"],
  "locationSearch": ["United States"],
  "timeRange": "7d",
  "limit": 25,
  "compact": true
}
```

#### Example prompts

```text
Use b2bsearch/linkedin-job-search-api with previewOnly true: how many "product manager" jobs were posted in the United Kingdom in the last 30 days, and how do they split by seniority, industry and city?
```

```text
Use b2bsearch/linkedin-job-search-api: titleSearch ["data engineer"], descriptionSearch ["kubernetes", "airflow"], locationSearch ["Germany"], timeRange 30d, removeAgency true, hasSalary true, 50 rows. Summarise the salary ranges and list the employers.
```

```text
Use b2bsearch/linkedin-job-search-api: titleSearch ["head of sales", "VP sales"], locationSearch ["United States"], organizationEmployeesGte 51, organizationEmployeesLte 1000, timeRange 7d, decisionMakers true, decisionMakerRoles ["founder", "cxo"], 40 rows. For each company give me the role, the posting date and the two people to contact.
```

```text
Use b2bsearch/linkedin-job-search-api: organizationSlugFilter ["stripe.com", "shopify.com"], timeRange 6m, status expired, expiredAfter 2026-10-01. Which roles did they close this month?
```

### Migrating from another LinkedIn jobs API

Your saved input runs as it is: the field names and values are the same.

| Their field | Here |
|---|---|
| `titleSearch`, `titleExclusionSearch`, `descriptionSearch`, `descriptionExclusionSearch`, `locationSearch`, `locationExclusionSearch`, `organizationSearch`, `organizationSlugFilter`, `organizationSlugExclusionFilter`, `organizationEmployeesGte`, `organizationEmployeesLte`, `organizationSizeFilter`, `industryFilter`, `industryExclusionFilter`, `seniorityFilter`, `aiEmploymentTypeFilter`, `hasSalary`, `removeAgency`, `recruiterOnly`, `timeRange`, `datePostedAfter`, `descriptionType`, `limit` | same names, same values |
| `aiExperienceLevelFilter` | same values, applied to the experience the posting states (not an AI estimate) |
| `timeRange: "1h"` | use `24h`: the database is reloaded after each data update, not every hour |
| `:*` prefix matching | not available: words match whole |
| `excludeATSDuplicate`, `populateAiRemoteLocation*`, `includeAi` | accepted and ignored: there are no career-site duplicates and no AI fields here |
| `organizationExclusionSearch` | not available: exclude by `organizationSlugExclusionFilter` |
| `aiWorkArrangementFilter`, `remote`, `aiVisaSponsorshipFilter`, `directApply`, `noDirectApply`, `aiTaxonomies*`, `aiLanguageFilter`, `hasNoLocation` | **not in this database**: a run that sets one stops before anything is charged and names the field |
| the Expired Jobs API | `status: "expired"` with `expiredAfter`, in the same run |
| `recruiterOnly` surcharge | none: the filter and the recruiter card are free |

The refusals are deliberate. A remote-only run that silently came back with office jobs would be a wrong answer sold as a right one.

### FAQ

#### How fresh is the data, and how do I run a sync?

The database holds the last 180 days of postings and is reloaded after each data update, not every hour. Every row says what the data runs to: `_input.dataAsOf` is the date of the newest posting at the time of your run. For new postings, schedule the Actor with `timeRange: "24h"` or `datePostedAfter` set to your last run; for closed ones, a second schedule with `status: "expired"` and `expiredAfter`.

#### Is this a scraper or an API?

An API over a database we fill and refresh ourselves. Nothing runs against LinkedIn when you press Start, which is why a search takes seconds, needs no cookies and charges nothing for a miss. The rows are what a scraper would give you, plus what a scraper cannot: the count before you pay, the employer's hiring pace and its decision makers.

#### Why does the description search need a narrow cut?

The posting texts are read one by one for the postings the other filters leave, and the service reads at most 500 of them per request. "Kubernetes anywhere in Germany this month" is a quarter of a million texts and is refused before anything is charged, with that number; "kubernetes" in the descriptions of *data engineer* postings in Germany this week, or of one employer's open roles, is a few hundred and runs in seconds. Put the role in `titleSearch` and the technology in `descriptionSearch`.

#### What does the employer's hiring pace tell me?

`employerHiring: true` puts the employer's signal on each job row: how many postings it has open now, how many it posted in the last 7, 30 and 90 days, when it last posted and which titles it posts most. An employer with 40 open roles and 20 posted this month is scaling; one with a single posting is filling a seat. It is free and comes from the same database.

#### Can I filter remote jobs, Easy Apply, visa sponsorship or the posting's language?

Not yet: none of these is recorded in the database, so the fields are refused rather than faked. A `titleSearch` for `remote` finds the postings that say so in the title: about 1 in 100 US postings of the last month (27,000 of 2.5 million on 26 October 2026), a sample rather than the remote market.

#### Are there duplicate jobs?

Each posting is one row with its own `jobId`, delivered and charged once per run even when it matches several of your search terms. An employer that posts the same role in several cities has several postings, as on the source; deduplicate on `title` + `companyId` for one row per role.

#### How is the employer-size filter applied?

On the employer's headcount on record. A posting at an employer outside the bounds, or with no headcount on record, is skipped and not charged; the run reads on until your `limit` is met or 2,000 postings have been skipped. The free preview counts every posting the other filters match: the bound is applied to the rows, so a bounded run returns fewer rows than the preview's count, and the preview says so.

#### Am I charged when nothing is found?

No. Empty searches, unusable employer entries, skipped postings and refused inputs are free rows with a `_status` and an explanation. Only `found` rows are charged.

#### Does it need cookies, a login or an API key?

No. The Actor does not sign in to any website and asks for no credentials.

### Related Actors: which one should you use?

| Need | Actor |
|---|---|
| Database-style job search: description keywords, exclusions, employer size, expired postings, decision makers | **LinkedIn Jobs Database API** (this Actor) |
| Jobs by title, location and company, in the input names of the best-known scraper | [Advanced LinkedIn Jobs Scraper](https://apify.com/b2bsearch/linkedin-jobs-scraper) |
| The companies hiring for a role, with their hiring pace and decision makers | [Companies Hiring Now](https://apify.com/b2bsearch/hiring-companies-finder) |
| Company domain → decision makers | [Decision Maker Email Finder by Domain](https://apify.com/b2bsearch/domain-to-decision-makers) |
| Company domain → current employees | [Company Employees](https://apify.com/b2bsearch/company-employees) |
| LinkedIn URL → full profile | [Profile Lookup](https://apify.com/b2bsearch/profile-lookup) |
| Filters → list of people | [People Database Search](https://apify.com/b2bsearch/people-database-search) |
| Filters → leads with an email | [B2B Leads Finder](https://apify.com/b2bsearch/b2b-leads-finder) |
| Filters → list of companies | [Company Database Search](https://apify.com/b2bsearch/company-database-search) |

### Free Apify plan

A run started from a free Apify plan delivers the first 100 results and stops;
the run's status line says so. Any paid Apify plan lifts the cap. The rows are
the same rows a paid run returns.

### Feedback and reviews

How did it go? A rating in the **Reviews** tab of this Actor tells the next
buyer what to expect; we read every word, good or bad. Got a wrong or stale
row? Open the **Issues** tab with the run ID. Issues are public, so leave out
emails, phones and names; the run ID is enough for us to find the row. We
check every report, fix what is ours to fix and answer in the thread.

### Disclaimer and permitted use

**Independent product.** This Actor is an independent tool. It is not affiliated with, endorsed by, or sponsored by LinkedIn Corporation. LinkedIn® is a trademark of its owner. It is named here only to describe the kind of public job postings and profile links this Actor returns.

**No platform access.** This Actor does not log in to, crawl or collect pages from LinkedIn or any other service. Every answer comes from our own database of job postings and business-contact records. It never returns passwords, messages, or content from non-public accounts.

**Permitted use.** Business purposes only: job market research, recruiting, sales prospecting, CRM enrichment and building job feeds. You may not use this Actor or its output to:

- stalk, harass, threaten, dox or publicly expose any person;
- decide on anyone's eligibility for credit, employment, housing or insurance. This Actor is not a consumer reporting agency and its output is not a consumer report under the U.S. Fair Credit Reporting Act;
- send unsolicited bulk messages, or place autodialed or prerecorded calls or texts without the consent the law requires;
- profile people by health, religion, political opinion, sexual orientation, ethnicity or union membership;
- build or resell a contact database from the results.

**Your responsibilities.** You decide what to search for and what to do with the result. You are responsible for having a lawful basis for that use and for complying with the laws that apply to you, including GDPR and UK GDPR, ePrivacy and PECR, CCPA/CPRA, CAN-SPAM, and the TCPA and Do Not Call rules. Honor every opt-out you receive.

**Removal requests.** To have a person's data removed, open an issue on
this Actor with only the profile link. Nothing else is needed, and the
record is removed from every listing.

**Accuracy.** Records can be incomplete or out of date. Output is provided as is. Check before you rely on it.

# Actor input Schema

## `titleSearch` (type: `array`):

Job titles to search for, one per line; a job whose title contains any line is kept. Whole words, any case. A line may use boolean search: AND, OR, NOT, "exact phrase", parentheses (for example: (backend OR platform) engineer NOT intern). Up to 10 lines. Example values: software engineer, data engineer.

## `locationSearch` (type: `array`):

Where the job is: countries by name or two-letter code (United States, Germany, gb, UK), US states (California), cities (Berlin; Austin, Texas). Any of them; no exact "City, State, Country" format to get right. A search needs a country here or an employer in Employer slugs. Up to 60.

## `limit` (type: `integer`):

How many jobs to deliver in this run (default 100; 0 = up to 10,000). This is your spend cap: $0.80 per 1,000 jobs delivered. Free Apify plan: up to 100.

## `previewOnly` (type: `boolean`):

Returns how many jobs match and their breakdown by country, seniority, employment type, industry, top employers, titles and cities. No job rows, no charge. Run it first to size a search or measure a market, then turn it off to get the jobs.

## `compact` (type: `boolean`):

Returns a short row: every plain column, long text (the description) cut to 300 characters, nested blocks left out. Made for AI agents and LLM pipelines with a context limit. Same price. Off by default.

## `timeRange` (type: `string`):

Jobs posted within this window, counted from the start of the run (default 7 days; 6m = everything the database holds, 180 days). The database is reloaded after each data update; every row says what date the data runs to. For a daily feed schedule the Actor with 24h.

## `titleExclusionSearch` (type: `array`):

Words or phrases the title must not contain, one per line (intern, "staff engineer"). Up to 10.

## `descriptionSearch` (type: `array`):

Words or phrases the job description must contain, one per line; any line matches. Put the role in Title search and the technology here (kubernetes, SAP, HubSpot). Needs an employer in Employer slugs, or a country with a time range of at most 30 days: the texts are read for the postings the other filters leave. Up to 10.

## `descriptionExclusionSearch` (type: `array`):

Words or phrases the description must not contain. Only together with Description search. Up to 10.

## `locationExclusionSearch` (type: `array`):

Whole countries to leave out, by name or two-letter code. Cities and states cannot be excluded.

## `organizationSlugFilter` (type: `array`):

Exact employers: the company page slug (tesla-motors), a company page URL, a website domain (stripe.com) or a numeric id. An employer list alone is a complete search, with Title search empty you get all of its postings. Up to 100.

## `organizationSearch` (type: `array`):

Employer names, matched as part of the recorded company name (Google matches Google Cloud). Several companies share a name, so use Employer slugs for an exact employer. Up to 20.

## `organizationSlugExclusionFilter` (type: `array`):

Employers to leave out: page slug, company page URL, website domain or numeric id. Up to 100.

## `organizationEmployeesGte` (type: `integer`):

Keep jobs at employers with at least this many employees on record. Employers with no headcount on record are skipped free.

## `organizationEmployeesLte` (type: `integer`):

Keep jobs at employers with at most this many employees on record.

## `organizationSizeFilter` (type: `array`):

Employer headcount buckets, any of them. Combined with the two size numbers above into one floor and one ceiling.

## `removeAgency` (type: `boolean`):

Drops postings by staffing and recruiting firms and job-board aggregators (by the posting's industry and by the employer's own card), and employers with far more postings than employees (at least 200 open, or 100 posted in 30 days, and more than two per employee). Off by default.

## `seniorityFilter` (type: `array`):

Seniority levels as the posting states them. Any of them.

## `employmentTypeFilter` (type: `array`):

Employment types, any of them. aiEmploymentTypeFilter is accepted as the same field.

## `industryFilter` (type: `array`):

Industries of the posting, by name (Software Development, Financial Services) or numeric id. An industry covers its sub-industries. Up to 30.

## `industryExclusionFilter` (type: `array`):

Industries to leave out, by name or numeric id. Up to 30.

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

Keep only postings that state a salary (about one in seven overall; half in the Netherlands, two in five in China).

## `salaryMin` (type: `integer`):

Keep postings whose stated yearly pay reaches this amount, in the salary currency. Postings without a stated salary never match.

## `salaryCurrency` (type: `string`):

Three-letter code the salary floor is in (default USD). A posting is compared in its own currency.

## `maxApplicants` (type: `string`):

Keep postings in the applicant buckets up to this ceiling. The data keeps applicant counts in buckets of 25; "Under 25" is the closest answer to "few applicants".

## `aiExperienceLevelFilter` (type: `array`):

Keep postings whose stated required experience falls in these ranges, as the posting states it (about one posting in five states one; the others never match). Adjacent ranges are joined.

## `recruiterOnly` (type: `boolean`):

Keep postings that name the recruiter or hiring manager (about one in nine; 28% in India, 17% in the UK, 7% in the US). Free; the recruiter card is on every such row.

## `datePostedAfter` (type: `string`):

Only jobs posted on or after this date (YYYY-MM-DD or a full timestamp). With a time range too, the later bound wins. Set it to your last run for a sync.

## `status` (type: `string`):

Active postings (default), expired ones (closed or past their valid-through date), or any. Expired with "Expired on or after" is the feed of what closed since a date, in the same Actor.

## `expiredAfter` (type: `string`):

With status expired or any: only postings that closed on or after this date (YYYY-MM-DD).

## `recruiter` (type: `string`):

"card" (default, free): name, headline and profile URL of the recruiter when the posting names one. "profile": their full career profile, $3.20 per 1,000 jobs that carry one. "none": leave the recruiter out.

## `employerHiring` (type: `boolean`):

Adds the employer's hiring signal to each job row, free: open postings now, postings in the last 7, 30 and 90 days, the date of its latest posting and its top titles of the last 30 days (employerOpenJobs, employerJobs7d/30d/90d, employerLastPostedAt, employerTopTitles30d). Tells a company scaling a team from one that posted once.

## `decisionMakers` (type: `boolean`):

After each job, adds the founders, C-level, VPs and directors of its employer as separate rows (each employer once per run): name, title, seniority, headline, profile URL, location, and the email on record when the contact tier is on. $3.20 per 1,000 people delivered; employers with nobody on record are free.

## `decisionMakerRoles` (type: `array`):

Which levels count as a decision maker. Rows are ordered founder + CEO first, then other founders and CEOs, the rest of the C-level, VPs, directors. Default: all four.

## `decisionMakersPerCompany` (type: `integer`):

How many people to add per employer, in rank order (default 3, maximum 25). Your spend cap per employer: $0.0032 per person.

## `decisionMakerTitleKeywords` (type: `array`):

Keep only decision makers whose job title contains any of these words, for example sales, engineering, talent (3-64 characters each, up to 10).

## `descriptionType` (type: `string`):

What the description columns carry: plain text (default), HTML, both, or none for small rows. Same price.

## Actor input object example

```json
{
  "titleSearch": [
    "software engineer"
  ],
  "locationSearch": [
    "United States"
  ],
  "limit": 25,
  "previewOnly": false,
  "compact": false,
  "timeRange": "7d",
  "removeAgency": false,
  "hasSalary": false,
  "salaryCurrency": "USD",
  "recruiterOnly": false,
  "status": "active",
  "recruiter": "card",
  "employerHiring": false,
  "decisionMakers": false,
  "decisionMakersPerCompany": 3,
  "descriptionType": "text"
}
```

# Actor output Schema

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

No description

# 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 = {
    "titleSearch": [
        "software engineer"
    ],
    "locationSearch": [
        "United States"
    ],
    "limit": 25
};

// Run the Actor and wait for it to finish
const run = await client.actor("b2bsearch/linkedin-job-search-api").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 = {
    "titleSearch": ["software engineer"],
    "locationSearch": ["United States"],
    "limit": 25,
}

# Run the Actor and wait for it to finish
run = client.actor("b2bsearch/linkedin-job-search-api").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 '{
  "titleSearch": [
    "software engineer"
  ],
  "locationSearch": [
    "United States"
  ],
  "limit": 25
}' |
apify call b2bsearch/linkedin-job-search-api --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,b2bsearch/linkedin-job-search-api"
        }
    }
}
```

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/hJNlupwSvPzRfg8X0/builds/QrQzxW3gkjtUiBcIV/openapi.json
