{
  "openapi": "3.0.1",
  "info": {
    "title": "LinkedIn Salary Scraper [💰$0.50/benchmark] — Pay by Job & City",
    "description": "One row per job title and location: pay percentiles, sample size and confidence, built from the pay ranges employers state on LinkedIn postings. Strongest in US pay-transparency states and the UK. No login. 💰 $0.50 per benchmark.",
    "version": "0.1",
    "x-build-id": "3gXaEdJU9hTDueBgr"
  },
  "servers": [
    {
      "url": "https://api.apify.com/v2"
    }
  ],
  "paths": {
    "/acts/blackfalcondata~linkedin-salary-scraper/run-sync-get-dataset-items": {
      "post": {
        "operationId": "run-sync-get-dataset-items-blackfalcondata-linkedin-salary-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/blackfalcondata~linkedin-salary-scraper/runs": {
      "post": {
        "operationId": "runs-sync-blackfalcondata-linkedin-salary-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/blackfalcondata~linkedin-salary-scraper/run-sync": {
      "post": {
        "operationId": "run-sync-blackfalcondata-linkedin-salary-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": {
          "benchmarkTitles": {
            "title": "💰 Job titles to benchmark",
            "type": "array",
            "description": "One salary benchmark per title and location: the run reads the postings for each and reports the pay ranges employers state on them (percentiles, sample size, source). Leave empty to scrape job listings without a benchmark.",
            "items": {
              "type": "string"
            }
          },
          "benchmarkLocations": {
            "title": "📍 Locations to benchmark",
            "type": "array",
            "description": "Each title is benchmarked in each location, e.g. \"California, United States\" or \"United Kingdom\". Pay ranges are common in US states with pay-transparency laws (California, New York, Colorado, Washington) and in the UK, and rare in much of Europe; thin cohorts are marked as small samples. Leave empty to use Location below.",
            "items": {
              "type": "string"
            }
          },
          "benchmarkJobsPerCohort": {
            "title": "🔢 Jobs per benchmark cohort",
            "minimum": 10,
            "maximum": 1000,
            "type": "integer",
            "description": "How many postings to read for each title and location (10-1000). More postings give steadier percentiles and take longer.",
            "default": 200
          },
          "minSampleSize": {
            "title": "🧮 Minimum pay ranges per benchmark",
            "minimum": 1,
            "maximum": 500,
            "type": "integer",
            "description": "A benchmark is published only when at least this many distinct pay ranges back it; below that the row reports its counts and no figures, and is not billed as a benchmark.",
            "default": 10
          },
          "includeJobs": {
            "title": "📄 Also deliver the job postings",
            "type": "boolean",
            "description": "Add every posting behind the benchmarks to the results (billed per job, like a job scrape). Off: you get one row per benchmark.",
            "default": false
          },
          "keywords": {
            "title": "🔍 Search keywords",
            "type": "string",
            "description": "Job search keywords (e.g. \"software engineer\", \"nurse\"). Leave blank to browse all jobs in the selected location."
          },
          "location": {
            "title": "📍 Location",
            "type": "string",
            "description": "City, state, region, or country (e.g. \"Berlin, Germany\", \"United States\"). LinkedIn resolves it for you — no IDs needed. Leave empty for global results."
          },
          "geoIds": {
            "title": "🌍 LinkedIn geoId (advanced)",
            "type": "array",
            "description": "Advanced/optional override — most users just use 📍 Location, which LinkedIn resolves automatically. For exact targeting, paste a LinkedIn jobs search URL into 🔗 Start URLs (the geoId is read for you), or copy the numeric geoId from a LinkedIn jobs URL. Each geoId becomes a separate query, deduped on jobId.",
            "default": [],
            "items": {
              "type": "string"
            }
          },
          "regions": {
            "title": "🗺 ISO-2 region codes",
            "type": "array",
            "description": "Two-letter country codes (e.g. \"US\", \"GB\", \"DE\"). Resolved to LinkedIn country geoIds. Use geoIds[] for unsupported markets.",
            "default": [],
            "items": {
              "type": "string"
            }
          },
          "regionPresets": {
            "title": "🌐 Region preset",
            "enum": [
              "nordic",
              "dach",
              "benelux",
              "uk-ireland",
              "eu-27",
              "gcc",
              "mena",
              "asean",
              "anglosphere",
              "latam",
              "nordics-extended"
            ],
            "type": "string",
            "description": "Pre-defined country grouping. Combined with regions[] if both are set."
          },
          "datePosted": {
            "title": "🗓 Date posted",
            "enum": [
              "anytime",
              "lastHour",
              "last24h",
              "last7d",
              "last30d"
            ],
            "type": "string",
            "description": "Filter by posting recency. \"lastHour\" is unique to this scraper.",
            "default": "anytime"
          },
          "jobType": {
            "title": "💼 Job type",
            "type": "array",
            "description": "Multi-select employment type filter.",
            "items": {
              "type": "string",
              "enum": [
                "fulltime",
                "parttime",
                "contract",
                "temporary",
                "internship",
                "volunteer",
                "other"
              ]
            },
            "default": []
          },
          "experienceLevel": {
            "title": "📈 Experience level",
            "type": "array",
            "description": "Multi-select seniority filter.",
            "items": {
              "type": "string",
              "enum": [
                "internship",
                "entry",
                "associate",
                "mid_senior",
                "director",
                "executive"
              ]
            },
            "default": []
          },
          "workType": {
            "title": "🏠 Work type",
            "type": "array",
            "description": "Multi-select onsite/remote/hybrid filter.",
            "items": {
              "type": "string",
              "enum": [
                "onsite",
                "remote",
                "hybrid"
              ]
            },
            "default": []
          },
          "salaryMin": {
            "title": "💰 Salary min",
            "minimum": 0,
            "type": "integer",
            "description": "Minimum annual salary in USD. Narrows LinkedIn's own search, then each job's stated range is converted to a yearly amount (hourly x 2080, daily x 260, weekly x 52, monthly x 12) and compared. A range in another currency or without a pay period cannot be compared: it is kept or left out together with jobs without salary (see Include jobs without salary) and marked not_comparable in salaryBoundCheck."
          },
          "salaryMax": {
            "title": "💰 Salary max",
            "minimum": 0,
            "type": "integer",
            "description": "Maximum annual salary in USD, compared the same way as Salary min (yearly amount, USD ranges only; other currencies and ranges without a period are marked not_comparable in salaryBoundCheck)."
          },
          "salaryIncludeUnknown": {
            "title": "Include jobs without salary",
            "type": "boolean",
            "description": "When Salary min or max is set, keep jobs that state no salary, and jobs whose range cannot be compared (another currency, or no pay period). Each kept job says which in salaryBoundCheck.",
            "default": true
          },
          "companies": {
            "title": "🏢 Companies — scrape all their jobs (IDs or URLs)",
            "type": "array",
            "description": "Scrape jobs from specific employers. Paste LinkedIn company-page URLs (e.g. https://www.linkedin.com/company/microsoft) or numeric companyIds — URLs are resolved for you, no ID lookup needed. Combine with 🔍 Keywords to filter within a company.",
            "default": [],
            "items": {
              "type": "string"
            }
          },
          "excludeCompanies": {
            "title": "🚫 Exclude companies",
            "type": "array",
            "description": "Company-name substrings to exclude (case-insensitive post-filter).",
            "default": [],
            "items": {
              "type": "string"
            }
          },
          "excludeKeywords": {
            "title": "🚫 Exclude keywords",
            "type": "array",
            "description": "Title substrings to exclude (case-insensitive post-filter).",
            "default": [],
            "items": {
              "type": "string"
            }
          },
          "easyApply": {
            "title": "⚡ Easy Apply only",
            "type": "boolean",
            "description": "Restrict results to LinkedIn Easy Apply postings.",
            "default": false
          },
          "removeAgency": {
            "title": "🚫 Remove staffing agencies",
            "type": "boolean",
            "description": "Heuristic post-filter on company name (\"recruitment\", \"staffing\", etc.).",
            "default": false
          },
          "distance": {
            "title": "📏 Distance (km/mi)",
            "minimum": 0,
            "type": "integer",
            "description": "Search radius around location. LinkedIn auto-detects unit (miles in US/UK/CA/AU/NZ; km elsewhere)."
          },
          "sortBy": {
            "title": "📊 Sort",
            "enum": [
              "recent",
              "relevant"
            ],
            "type": "string",
            "description": "Sort order. \"recent\" is recommended for incremental feeds.",
            "default": "recent"
          },
          "startUrls": {
            "title": "🔗 Advanced: start URLs",
            "type": "array",
            "description": "Paste LinkedIn job URLs from your browser. Two kinds work: a job SEARCH URL (e.g. .../jobs/search?keywords=…) reuses all of its filters as the query, or an individual JOB POSTING URL (e.g. .../jobs/view/4012345678) is scraped directly with full detail. Mix both freely.",
            "default": [],
            "items": {
              "type": "object",
              "required": [
                "url"
              ],
              "properties": {
                "url": {
                  "type": "string",
                  "title": "URL of a web page",
                  "format": "uri"
                }
              }
            }
          },
          "proxyConfiguration": {
            "title": "🛡 Your own proxy URLs (optional)",
            "type": "object",
            "description": "Leave empty — the actor picks its own connection. Only if you must route requests through your own proxies, enter them as {\"proxyUrls\": [\"http://user:pass@host:port\"]}. Other proxy settings are ignored."
          },
          "linkedinHost": {
            "title": "🌐 LinkedIn host",
            "type": "string",
            "description": "Subdomain (e.g. \"www\", \"de\"). Affects default geo-routing + UI labels.",
            "default": "www"
          },
          "outputLanguage": {
            "title": "🗣 Accept-Language",
            "type": "string",
            "description": "HTTP Accept-Language header. Default en-US for parsing-cleanliness.",
            "default": "en-US,en;q=0.9"
          },
          "incrementalMode": {
            "title": "🔁 Incremental mode",
            "type": "boolean",
            "description": "Persist seen-jobIds across runs; emit only NEW + UPDATED. Requires stateKey.",
            "default": false
          },
          "stateKey": {
            "title": "🔑 State key",
            "type": "string",
            "description": "Optional stable identifier for the tracked search universe. Leave empty to auto-derive a stable identifier from your search inputs — different keyword/location/filter combinations get isolated state automatically."
          },
          "allowNonIncrementalFallback": {
            "title": "↩️ Allow Non-Incremental Fallback",
            "type": "boolean",
            "description": "If incremental mode is requested but the state store is not accessible on this account, fall back to a non-incremental run instead of failing. Default: fail loudly so missing state is not silently ignored.",
            "default": false
          },
          "outputMode": {
            "title": "📤 Output mode",
            "enum": [
              "all",
              "new-only",
              "changed-only"
            ],
            "type": "string",
            "description": "Which items to emit when in incrementalMode.",
            "default": "all"
          },
          "emitUnchanged": {
            "title": "♻️ Emit UNCHANGED items",
            "type": "boolean",
            "description": "Include items that haven't changed since last run.",
            "default": false
          },
          "emitExpired": {
            "title": "⚰️ Emit EXPIRED items",
            "type": "boolean",
            "description": "Include items that disappeared from search results.",
            "default": false
          },
          "skipReposts": {
            "title": "Skip detected reposts",
            "type": "boolean",
            "description": "Suppress jobs with the same content as a previously-seen but inactive listing.",
            "default": false
          },
          "enrichDetails": {
            "title": "🔬 Enrich with detail page (salary source)",
            "type": "boolean",
            "description": "Fetch each job's detail page to extract the salary / pay range plus full description, seniorityLevel, employmentType, jobFunction, industry, and applicantCount. On by default — this is where salary data comes from. Adds 1 HTTP request per job.",
            "default": true
          },
          "scrapeCompany": {
            "title": "🏢 Scrape company details",
            "type": "boolean",
            "description": "For each job, fetch the employer's public LinkedIn company page and add company description, website, employee count, logo, and address. Fetched once per unique company.",
            "default": false
          },
          "discoverRelated": {
            "title": "🔭 Expand via relatedJobs",
            "type": "boolean",
            "description": "After the main search, fetch LinkedIn's related-jobs feed for the first N results to discover roles that don't surface on the keyword search. Useful for thin markets.",
            "default": false
          },
          "relatedSeedCount": {
            "title": "relatedJobs seed count",
            "minimum": 0,
            "maximum": 100,
            "type": "integer",
            "description": "How many of the first search results are used as seeds for related-jobs expansion. Each seed yields up to 10 candidates.",
            "default": 5
          },
          "telegramToken": {
            "title": "Telegram bot token",
            "type": "string",
            "description": "Bot token from @BotFather. Leave empty to disable Telegram notifications."
          },
          "telegramChatId": {
            "title": "💬 Telegram chat ID",
            "type": "string",
            "description": "Numeric chat or channel ID where notifications should be sent."
          },
          "discordWebhookUrl": {
            "title": "Discord webhook URL",
            "type": "string",
            "description": "Channel webhook URL. Leave empty to disable Discord notifications."
          },
          "slackWebhookUrl": {
            "title": "Slack webhook URL",
            "type": "string",
            "description": "Incoming webhook URL. Leave empty to disable Slack notifications."
          },
          "whatsappAccessToken": {
            "title": "WhatsApp Cloud API access token",
            "type": "string",
            "description": "Permanent System User token from Meta Business."
          },
          "whatsappPhoneNumberId": {
            "title": "WhatsApp phone-number ID",
            "type": "string",
            "description": "Numeric phone-number ID from the Meta dashboard."
          },
          "whatsappTo": {
            "title": "WhatsApp recipient (E.164)",
            "type": "string",
            "description": "Recipient phone number in E.164 format (e.g. \"4561234567\")."
          },
          "webhookUrl": {
            "title": "Generic webhook URL (n8n / Make / Zapier)",
            "type": "string",
            "description": "Receives a JSON POST of {metadata, items} for each batch."
          },
          "webhookHeaders": {
            "title": "Webhook headers",
            "type": "object",
            "description": "Additional HTTP headers to include with the generic webhook (e.g. Authorization)."
          },
          "notificationLimit": {
            "title": "Max items per notification batch",
            "minimum": 1,
            "maximum": 50,
            "type": "integer",
            "description": "Cap on items included in each notification message.",
            "default": 5
          },
          "notifyOnlyChanges": {
            "title": "Notify only NEW/UPDATED",
            "type": "boolean",
            "description": "When in incrementalMode, suppress notifications for UNCHANGED items.",
            "default": false
          },
          "compact": {
            "title": "Compact output",
            "type": "boolean",
            "description": "Emit only core fields (keeps cost the same; reduces dataset size).",
            "default": false
          },
          "descriptionMaxLength": {
            "title": "Description max length",
            "minimum": 0,
            "type": "integer",
            "description": "Truncate description (0 = no truncation). Only relevant when enrichDetails=true.",
            "default": 0
          },
          "phoneExtractionMode": {
            "title": "Phone-extraction mode",
            "enum": [
              "strict",
              "lenient"
            ],
            "type": "string",
            "description": "\"strict\" requires Tel:/+CC prefix; \"lenient\" also picks up bare local-format numbers.",
            "default": "strict"
          },
          "maxResults": {
            "title": "💯 Max results",
            "minimum": 0,
            "type": "integer",
            "description": "Cap on emitted items (0 = unlimited). Runs above 200 results, or unlimited, start with 1024 MB of memory so they finish faster; up to 200 start with 512 MB.",
            "default": 100
          },
          "descriptionFormat": {
            "title": "Description format",
            "enum": [
              "all",
              "text",
              "html",
              "markdown"
            ],
            "type": "string",
            "description": "Pick a single description representation. `all` keeps every variant; `text` / `html` / `markdown` drop the others.",
            "default": "all"
          },
          "excludeEmptyFields": {
            "title": "Exclude empty fields from output",
            "type": "boolean",
            "description": "Drop null, empty-string, and empty-array fields from each record before push. Smaller, cleaner payloads for AI agents and dashboards. On by default; turn off to always emit every field (including empty ones).",
            "default": true
          },
          "appConnector": {
            "title": "Send results to Notion (or another connected app)",
            "type": "string",
            "description": "Optional. Pick a connected app under Settings → API & Integrations to receive your results. Notion is supported today (a run-summary page); other MCP connectors are best-effort as Apify expands its catalog."
          },
          "mcpIssueTeam": {
            "title": "Issue tracker team",
            "type": "string",
            "description": "Only when the connected app is an issue tracker: the team (name or ID) the summary issue is created under, if that app requires one."
          },
          "cityName": {
            "title": "🏙️ City Name",
            "type": "string",
            "description": "City or region to search in (e.g. \"Berlin\", \"Madrid\"). Alias for Location — either field works."
          },
          "query": {
            "title": "🔍 Search Term(s)",
            "type": "string",
            "description": "Listing search keywords. Enter a single term or a JSON array for multi-query runs."
          }
        }
      },
      "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
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}