{
  "openapi": "3.0.1",
  "info": {
    "title": "LinkedIn Jobs Scraper",
    "description": "LinkedIn job scraper tool: LinkedIn job listings and job postings, no login or cookies. Search LinkedIn jobs by title, location; LinkedIn job data, applicant count, pay if shown, full description. LinkedIn job alerts with webhooks. LinkedIn jobs CSV, JSON, Excel export; LinkedIn job search API.",
    "version": "0.1",
    "x-build-id": "oFhS8pa1XxsUeohkJ"
  },
  "servers": [
    {
      "url": "https://api.apify.com/v2"
    }
  ],
  "paths": {
    "/acts/flash_scraper~linkedin-jobs-scraper/run-sync-get-dataset-items": {
      "post": {
        "operationId": "run-sync-get-dataset-items-flash_scraper-linkedin-jobs-scraper",
        "x-openai-isConsequential": false,
        "summary": "Executes an Actor, waits for its completion, and returns Actor's dataset items in response.",
        "tags": [
          "Run Actor"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/inputSchema"
              }
            }
          }
        },
        "parameters": [
          {
            "name": "token",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Enter your Apify token here"
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          }
        }
      }
    },
    "/acts/flash_scraper~linkedin-jobs-scraper/runs": {
      "post": {
        "operationId": "runs-sync-flash_scraper-linkedin-jobs-scraper",
        "x-openai-isConsequential": false,
        "summary": "Executes an Actor and returns information about the initiated run in response.",
        "tags": [
          "Run Actor"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/inputSchema"
              }
            }
          }
        },
        "parameters": [
          {
            "name": "token",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Enter your Apify token here"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/runsResponseSchema"
                }
              }
            }
          }
        }
      }
    },
    "/acts/flash_scraper~linkedin-jobs-scraper/run-sync": {
      "post": {
        "operationId": "run-sync-flash_scraper-linkedin-jobs-scraper",
        "x-openai-isConsequential": false,
        "summary": "Executes an Actor, waits for completion, and returns the OUTPUT from Key-value store in response.",
        "tags": [
          "Run Actor"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/inputSchema"
              }
            }
          }
        },
        "parameters": [
          {
            "name": "token",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Enter your Apify token here"
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "inputSchema": {
        "type": "object",
        "properties": {
          "searchQueries": {
            "title": "Job titles / keywords (what)",
            "type": "array",
            "description": "Job titles, skills, or company keywords to search — one per line. e.g. 'data analyst', 'react developer'. A LinkedIn search URL pasted here is read like searchUrls.",
            "default": [
              "data analyst"
            ],
            "items": {
              "type": "string"
            }
          },
          "searchUrls": {
            "title": "LinkedIn job-search URLs (optional)",
            "type": "array",
            "description": "Paste LinkedIn job-search URLs (linkedin.com/jobs/search?...). When set they replace searchQueries, location, locations and geoId; maxItems applies per URL. Unused URL filters are named in the run.",
            "default": [],
            "items": {
              "type": "string"
            }
          },
          "location": {
            "title": "Location (where)",
            "type": "string",
            "description": "City, state, country, or zip to search within — e.g. 'United States', 'London', 'Remote'. Ignored when `locations`, `geoId` or `searchUrls` is set.",
            "default": "United States"
          },
          "locations": {
            "title": "Locations (one search per place)",
            "type": "array",
            "description": "Optional. Search each of these places separately INSTEAD of `location` — e.g. 'Austin, TX', 'Dallas, TX', 'Houston, TX'. LinkedIn's public search stops at 800 results per search, so a list of cities is how one run goes past that wall for a whole state or country; a posting found under two places is delivered (and billed) once. `maxItems` applies to EACH place. Up to 25 places per run — extra entries are not searched and the run says so. Leave empty to search `location`.",
            "default": [],
            "items": {
              "type": "string"
            }
          },
          "geoId": {
            "title": "LinkedIn geoId (optional)",
            "type": "string",
            "description": "Optional. The numeric geoId from a LinkedIn job-search URL (the number after geoId=, e.g. 103644278 = United States). When set, `location` and `locations` are ignored and LinkedIn's own place id pins the search, so ambiguous names (Paris, Cambridge, Georgia) resolve deterministically. Measured 2026-08-29 from a home IP: geoId=103644278 with no location returned the same listings as location 'United States'. A non-numeric value is ignored (the run says so) and `location` is used."
          },
          "datePosted": {
            "title": "Date posted",
            "enum": [
              "",
              "r86400",
              "r604800",
              "r2592000"
            ],
            "type": "string",
            "description": "Only jobs posted within this window.",
            "default": ""
          },
          "experienceLevel": {
            "title": "Experience level",
            "type": "array",
            "description": "Keep only jobs at these seniority levels (leave empty for all). Checked on each job page's own 'Seniority level' (or, when the poster set none, on clear title words like Senior, Director or Junior): a job at another level, or whose page could not be read, is left out and not billed; a job with no level anywhere is kept.",
            "items": {
              "type": "string",
              "enum": [
                "1",
                "2",
                "3",
                "4",
                "5"
              ],
              "enumTitles": [
                "Internship",
                "Entry level",
                "Associate",
                "Mid-Senior level",
                "Director"
              ]
            },
            "default": []
          },
          "contractType": {
            "title": "Employment type",
            "type": "array",
            "description": "Employment type HINT (leave empty for all). Since LinkedIn's August 2026 AI search (measured 2026-08-29) workplace type and job type are not honoured at the source; the actor converts them to search keywords plus a title/location check — verify with isRemote. Codes become search words: Part-time → 'part-time', Contract → 'contract', Temporary → 'temporary', Internship → 'internship'; Full-time adds none. The row's employmentType, read from the job page, is the truth.",
            "items": {
              "type": "string",
              "enum": [
                "F",
                "P",
                "C",
                "T",
                "I"
              ],
              "enumTitles": [
                "Full-time",
                "Part-time",
                "Contract",
                "Temporary",
                "Internship"
              ]
            },
            "default": []
          },
          "remote": {
            "title": "Work arrangement",
            "type": "array",
            "description": "Work arrangement HINT (leave empty for all). Since LinkedIn's August 2026 AI search (measured 2026-08-29) workplace type and job type are not honoured at the source; the actor converts them to search keywords plus a title/location check — verify with isRemote. Remote → 'remote', Hybrid → 'hybrid'; On-site adds none. Remote alone (just '2') also keeps only search cards whose title or location says remote/WFH, checked BEFORE the job pages are read, so the rest are neither fetched nor billed.",
            "items": {
              "type": "string",
              "enum": [
                "1",
                "2",
                "3"
              ],
              "enumTitles": [
                "On-site",
                "Remote",
                "Hybrid"
              ]
            },
            "default": []
          },
          "companyNames": {
            "title": "Companies",
            "type": "array",
            "description": "Keep only listings whose company name, as printed on the search card, contains one of these (case-insensitive substring: 'Google' keeps Google and Google Cloud, drops Alphabet). Checked on the search cards BEFORE the job pages are read, so a dropped listing is neither fetched nor billed. A subsidiary or a differently spelled legal name is dropped — use `companyId` for an exact pin. Leave empty for all.",
            "default": [],
            "items": {
              "type": "string"
            }
          },
          "companyId": {
            "title": "Company IDs",
            "type": "array",
            "description": "Filter by LinkedIn numeric company IDs (from a company page URL). Leave empty for all.",
            "default": [],
            "items": {
              "type": "string"
            }
          },
          "maxItems": {
            "title": "Max jobs per search",
            "minimum": 1,
            "maximum": 1000,
            "type": "integer",
            "description": "Maximum number of jobs per search (1-1000): per search query and, when `locations` is set, per place — 3 queries x 4 places can deliver up to 12 x this figure (a posting found under two places is billed once). With `searchUrls`: per URL (a URL's f_PP cities share it).",
            "default": 100
          },
          "requireSalary": {
            "title": "Only jobs with a salary",
            "type": "boolean",
            "description": "Keep only listings whose public job page shows a base-pay range (varies by posting and state; on the 6 pages measured 2026-08-29, 2 showed a base-pay range). Listings without advertised pay — and listings whose job page could not be read — are dropped.",
            "default": false
          },
          "minSalary": {
            "title": "Minimum salary (annualized)",
            "minimum": 0,
            "type": "integer",
            "description": "Keep only listings whose advertised pay (salaryMax, else salaryMin) is at least this much per year; hourly pay is annualized (x2080). Listings showing no pay are dropped, like requireSalary. 0 = no filter.",
            "default": 0
          },
          "easyApplyOnly": {
            "title": "Easy Apply only",
            "type": "boolean",
            "description": "Keep only jobs that support LinkedIn Easy Apply — applied at the source (measured 2026-08-29 from a home IP; the post-fetch check stays as a safety net), so the run asks LinkedIn for Easy Apply postings instead of reading every job page to find them.",
            "default": false
          },
          "maxApplicants": {
            "title": "Max applicants",
            "minimum": 0,
            "type": "integer",
            "description": "Keep only jobs with at most this many applicants (low-competition roles; 0 = no filter).",
            "default": 0
          },
          "titleInclude": {
            "title": "Title must contain (any of)",
            "type": "array",
            "description": "Keep only listings whose job title contains at least one of these words or phrases (case-insensitive). Checked on the search cards BEFORE the job pages are read, so a dropped listing is neither fetched nor billed. Leave empty for all.",
            "default": [],
            "items": {
              "type": "string"
            }
          },
          "titleExclude": {
            "title": "Title must not contain",
            "type": "array",
            "description": "Drop listings whose job title contains any of these words or phrases (case-insensitive) — e.g. 'intern', 'manager', 'clearance'. Checked on the search cards BEFORE the job pages are read, so a dropped listing is neither fetched nor billed. Leave empty for none.",
            "default": [],
            "items": {
              "type": "string"
            }
          },
          "excludeAgencies": {
            "title": "Exclude staffing agencies",
            "type": "boolean",
            "description": "Drop listings whose company name looks like a staffing / recruiting agency (name contains staffing, recruit, talent, headhunt, manpower, personnel, placement, consultancy, resourcing, workforce, ...). A name-based heuristic: 'Deloitte Consulting' passes, 'TalentBridge Staffing' is dropped. Checked on the search cards BEFORE the job pages are read, so a dropped listing is neither fetched nor billed.",
            "default": false
          },
          "onlyNewJobs": {
            "title": "Only new jobs (monitor mode)",
            "type": "boolean",
            "description": "ON: the run remembers every listing it delivers for this exact search (queries + location + filters) in a key-value store in YOUR account and, on later runs, delivers — and bills — only listings that are new since. The first run is the baseline. A quiet run delivers nothing and bills no results. OFF (default): every run returns everything it finds. With searchUrls, the URLs' search filters are the key, not their page or tracking parameters.",
            "default": false
          },
          "descriptionFormat": {
            "title": "Description format",
            "enum": [
              "text",
              "markdown",
              "html"
            ],
            "type": "string",
            "description": "How the posting's description is written into `descriptionText`. `text` (default): plain text, whitespace collapsed. `markdown`: **bold**, *italic*, `- ` bullets, `1.` numbers, `[text](url)` links and line breaks from the job page's own markup — best for an LLM or a spreadsheet. `html`: the description block as LinkedIn serves it. Same page, no extra fetch, no price change; the column keeps its name and position, and job_score uses the plain text in every format (details in the README).",
            "default": "text"
          },
          "proxyConfiguration": {
            "title": "Proxy (optional)",
            "type": "object",
            "description": "Optional. Leave empty and every request goes straight from the Apify container; a search can then stop early on HTTP 429 (rate limited). Set a proxy (Apify RESIDENTIAL, a country, or your own proxy URLs) when LinkedIn gates your region with sign-in pages or HTTP 999, or on heavy schedules: each connection then gets its own proxy session, and every retry after a block or a network error moves to a NEW session (a fresh exit IP) instead of re-hitting the same address."
          },
          "webhookUrl": {
            "title": "Alert webhook URL (Slack, Discord, n8n, Make, Zapier…)",
            "type": "string",
            "description": "Optional. When at least one row is delivered, the run POSTs a digest to this URL: a Slack incoming webhook gets a text message, a Discord webhook gets a message, any other URL (n8n / Make / Zapier catch hook, your own endpoint) gets JSON with the counts, console links and the first 20 rows. Quiet runs send nothing. Pair it with onlyNewJobs on a schedule for new-job alerts. Delivery is best-effort: a failure is reported in the status message and RUN_SUMMARY.webhook and never fails the run."
          }
        }
      },
      "runsResponseSchema": {
        "type": "object",
        "properties": {
          "data": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string"
              },
              "actId": {
                "type": "string"
              },
              "userId": {
                "type": "string"
              },
              "startedAt": {
                "type": "string",
                "format": "date-time",
                "example": "2025-01-08T00:00:00.000Z"
              },
              "finishedAt": {
                "type": "string",
                "format": "date-time",
                "example": "2025-01-08T00:00:00.000Z"
              },
              "status": {
                "type": "string",
                "example": "READY"
              },
              "meta": {
                "type": "object",
                "properties": {
                  "origin": {
                    "type": "string",
                    "example": "API"
                  },
                  "userAgent": {
                    "type": "string"
                  }
                }
              },
              "stats": {
                "type": "object",
                "properties": {
                  "inputBodyLen": {
                    "type": "integer",
                    "example": 2000
                  },
                  "rebootCount": {
                    "type": "integer",
                    "example": 0
                  },
                  "restartCount": {
                    "type": "integer",
                    "example": 0
                  },
                  "resurrectCount": {
                    "type": "integer",
                    "example": 0
                  },
                  "computeUnits": {
                    "type": "integer",
                    "example": 0
                  }
                }
              },
              "options": {
                "type": "object",
                "properties": {
                  "build": {
                    "type": "string",
                    "example": "latest"
                  },
                  "timeoutSecs": {
                    "type": "integer",
                    "example": 300
                  },
                  "memoryMbytes": {
                    "type": "integer",
                    "example": 1024
                  },
                  "diskMbytes": {
                    "type": "integer",
                    "example": 2048
                  }
                }
              },
              "buildId": {
                "type": "string"
              },
              "defaultKeyValueStoreId": {
                "type": "string"
              },
              "defaultDatasetId": {
                "type": "string"
              },
              "defaultRequestQueueId": {
                "type": "string"
              },
              "buildNumber": {
                "type": "string",
                "example": "1.0.0"
              },
              "containerUrl": {
                "type": "string"
              },
              "usage": {
                "type": "object",
                "properties": {
                  "ACTOR_COMPUTE_UNITS": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATASET_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATASET_WRITES": {
                    "type": "integer",
                    "example": 0
                  },
                  "KEY_VALUE_STORE_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "KEY_VALUE_STORE_WRITES": {
                    "type": "integer",
                    "example": 1
                  },
                  "KEY_VALUE_STORE_LISTS": {
                    "type": "integer",
                    "example": 0
                  },
                  "REQUEST_QUEUE_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "REQUEST_QUEUE_WRITES": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATA_TRANSFER_INTERNAL_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATA_TRANSFER_EXTERNAL_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "PROXY_SERPS": {
                    "type": "integer",
                    "example": 0
                  },
                  "PROXY_UNBLOCKER_UNITS": {
                    "type": "integer",
                    "example": 0
                  }
                }
              },
              "usageTotalUsd": {
                "type": "number",
                "example": 0.00005
              },
              "usageUsd": {
                "type": "object",
                "properties": {
                  "ACTOR_COMPUTE_UNITS": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATASET_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATASET_WRITES": {
                    "type": "integer",
                    "example": 0
                  },
                  "KEY_VALUE_STORE_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "KEY_VALUE_STORE_WRITES": {
                    "type": "number",
                    "example": 0.00005
                  },
                  "KEY_VALUE_STORE_LISTS": {
                    "type": "integer",
                    "example": 0
                  },
                  "REQUEST_QUEUE_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "REQUEST_QUEUE_WRITES": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATA_TRANSFER_INTERNAL_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATA_TRANSFER_EXTERNAL_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "PROXY_SERPS": {
                    "type": "integer",
                    "example": 0
                  },
                  "PROXY_UNBLOCKER_UNITS": {
                    "type": "integer",
                    "example": 0
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}