{
  "openapi": "3.0.1",
  "info": {
    "title": "Job Board Scraper & Jobs API: LinkedIn Jobs, Indeed, Glassdoor",
    "description": "LinkedIn, Indeed, Glassdoor scraper & job board aggregator: scrape jobs on up to 12 boards incl. The Muse job board, deduped. Job scraping tool, job scraper tool, job search aggregator for new job postings data; scheduled job monitoring for LinkedIn job alerts. Multi source job scraper, no API key.",
    "version": "0.1",
    "x-build-id": "LfpfGcpUiNbMaXMpo"
  },
  "servers": [
    {
      "url": "https://api.apify.com/v2"
    }
  ],
  "paths": {
    "/acts/flash_scraper~multi-jobboard-scraper/run-sync-get-dataset-items": {
      "post": {
        "operationId": "run-sync-get-dataset-items-flash_scraper-multi-jobboard-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~multi-jobboard-scraper/runs": {
      "post": {
        "operationId": "runs-sync-flash_scraper-multi-jobboard-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~multi-jobboard-scraper/run-sync": {
      "post": {
        "operationId": "run-sync-flash_scraper-multi-jobboard-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": {
          "preset": {
            "title": "Preset",
            "enum": [
              "",
              "salary_research",
              "competitor_intel",
              "remote_only",
              "fresh_postings",
              "recruiter_leads"
            ],
            "type": "string",
            "description": "Fills only options left at their default (yours win; <code>RUN_SUMMARY.preset_applied</code> lists changes). Salary research: salary rows only, annualized, top pay first. Competitor hiring intel: filters nothing without <b>Only these companies</b>. Remote-only sweep: turns on <b>Remote jobs only</b>, the one preset that can raise your bill. Fresh postings only: drops jobs over 7 days old. Recruiter lead-gen: drops staffing-agency reposts. Dropped rows are never billed. (details in the README)",
            "default": ""
          },
          "roleSelect": {
            "title": "Role (quick pick)",
            "enum": [
              "",
              "software engineer",
              "data analyst",
              "registered nurse",
              "sales representative",
              "product designer",
              "devops engineer",
              "machine learning engineer",
              "project manager",
              "accountant",
              "truck driver",
              "retail associate",
              "civil engineer",
              "lab technician",
              "customer support",
              "content writer",
              "security engineer",
              "financial analyst",
              "teacher",
              "chef",
              "electrician"
            ],
            "type": "string",
            "description": "Pick a common job title instead of typing one, e.g. <code>Nurse</code>. Leave it on <b>Custom</b> to use the <b>Search term</b> box below — and note the reverse: picking a role here <b>overrides</b> that box, and only <b>Search terms (multiple)</b> outranks it. This is not a fixed taxonomy: the choice is sent to the boards as plain keywords, exactly as if you had typed them.",
            "default": ""
          },
          "citySelect": {
            "title": "City (quick pick)",
            "enum": [
              "",
              "Remote",
              "New York, NY",
              "San Francisco, CA",
              "Los Angeles, CA",
              "Chicago, IL",
              "Austin, TX",
              "Seattle, WA",
              "Boston, MA",
              "Washington, DC",
              "Atlanta, GA",
              "Dallas, TX",
              "Denver, CO",
              "Miami, FL",
              "Phoenix, AZ",
              "Houston, TX",
              "Toronto, ON",
              "London",
              "Berlin",
              "Amsterdam",
              "Dublin",
              "Paris",
              "Sydney",
              "Bengaluru",
              "Singapore"
            ],
            "type": "string",
            "description": "Pick a metro instead of typing one, e.g. <code>Austin, TX</code>. <b>Custom</b> uses the <b>Location</b> box; a city picked here overrides that box, and <b>Locations (multiple)</b> overrides both. A non-US metro also switches <b>Indeed/Glassdoor country</b> to that country unless you set it yourself (logged and in <code>RUN_SUMMARY</code>). <b>Remote</b> only searches the word <code>Remote</code> as the location; turn on <b>Remote jobs only</b> for the strict filter and the remote-only boards.",
            "default": ""
          },
          "searchTerm": {
            "title": "Search term",
            "type": "string",
            "description": "Enter the job title or keywords sent to every selected board, e.g. <code>registered nurse</code>. Ignored when you pick a <b>Role (quick pick)</b> above or fill <b>Search terms (multiple)</b> below; boards treat this as free text, so quotes and boolean operators are not guaranteed to work.",
            "default": "software engineer"
          },
          "searchTerms": {
            "title": "Search terms (multiple)",
            "type": "array",
            "description": "Run up to 5 searches in one go, merged and de-duplicated so a job posting found by two terms is billed once. Overrides both <b>Search term</b> and <b>Role (quick pick)</b>; terms beyond the 5th are reported in the run status and in <code>RUN_SUMMARY.ignored_search_terms</code>, never dropped silently.",
            "default": [],
            "items": {
              "type": "string"
            }
          },
          "location": {
            "title": "Location",
            "type": "string",
            "description": "Enter the city, state or country to search in, e.g. <code>New York, NY</code>. Ignored when you pick a <b>City (quick pick)</b> above or fill <b>Locations (multiple)</b> below; leave it empty to search anywhere, and remember that one country-wide value returns a single capped batch of job postings per board while three cities return three.",
            "default": "New York, NY"
          },
          "locations": {
            "title": "Locations (multiple)",
            "type": "array",
            "description": "Search several places in one run, e.g. <code>Austin, TX</code>, <code>Denver, CO</code>: the way past a board's per-query cap. Replaces <b>Location</b> and <b>City (quick pick)</b>. Capped at 10 locations and 50 term × location searches, reported in <code>RUN_SUMMARY</code>. <b>Cost:</b> each pair asks every board for up to <b>Max job postings per board</b>, so 3 terms × 3 locations × 3 boards can bill up to 9× one search; a job found twice bills once.",
            "default": [],
            "items": {
              "type": "string"
            }
          },
          "sites": {
            "title": "Job boards",
            "type": "array",
            "description": "Default: LinkedIn, Indeed, Glassdoor, The Muse (no salary data). The seven remote-only boards auto-join only when <b>Remote jobs only</b> is on and this list is exactly the default. DevITjobs US is opt-in. Naukri and BDJobs bill per row but search only a place in India / Bangladesh (e.g. Bengaluru, Dhaka); any other location bills nothing on them. The three boards marked <b>blocked at source</b> and DevITjobs UK (discontinued) return nothing and bill nothing. (details in the README)",
            "items": {
              "type": "string",
              "enum": [
                "linkedin",
                "indeed",
                "glassdoor",
                "muse",
                "remotive",
                "jobicy",
                "himalayas",
                "hn_hiring",
                "devitjobs_us",
                "devitjobs_uk",
                "remoteok",
                "weworkremotely",
                "working_nomads",
                "google",
                "zip_recruiter",
                "bayt",
                "bdjobs",
                "naukri"
              ],
              "enumTitles": [
                "LinkedIn",
                "Indeed",
                "Glassdoor",
                "The Muse",
                "Remotive · remote-only",
                "Jobicy · remote-only",
                "Himalayas · remote-only",
                "HN Who-is-Hiring · remote-only",
                "DevITjobs US · tech, ~100% salary",
                "DevITjobs UK · discontinued upstream 2026-08-29",
                "Remote OK · remote-only",
                "We Work Remotely · remote-only",
                "Working Nomads · remote-only",
                "Google Jobs · blocked at source",
                "ZipRecruiter · blocked at source",
                "Bayt / MENA · blocked at source",
                "BDJobs / Bangladesh · places in Bangladesh only, billed per row",
                "Naukri / India · places in India only, billed per row"
              ]
            },
            "default": [
              "linkedin",
              "indeed",
              "glassdoor",
              "muse"
            ]
          },
          "searchUrls": {
            "title": "Search URLs",
            "type": "array",
            "description": "Paste job-search URLs to skip the form: LinkedIn (<code>linkedin.com/jobs/search</code>), Indeed (any country sub-domain) or Glassdoor. Replaces <b>Search term</b>, <b>Locations</b> and <b>Job boards</b>; each URL scrapes its own board with its own filters. LinkedIn ignores <code>f_WT</code> / <code>f_JT</code>, so also set <b>Remote jobs only</b> / <b>Job type</b> here. A URL that cannot be parsed is skipped and named in <code>RUN_SUMMARY.search_url_errors</code>. (details in the README)",
            "default": [],
            "items": {
              "type": "string"
            }
          },
          "atsCompanies": {
            "title": "Watch specific companies (ATS boards)",
            "type": "array",
            "description": "Up to 20 companies, e.g. <code>Stripe</code>, read from their own careers boards (Greenhouse, Lever, Ashby, Recruitee, BambooHR or Workable). <b>Job boards</b> still run and bill; <code>sites: []</code> skips them. Default <b>Search term</b>: whole boards; your own term keeps and bills only matching roles. Companies on none of the six cost nothing. <b>Max job postings per board</b> caps rows per company. BambooHR dates and BambooHR/Workable descriptions need <b>Full LinkedIn job details</b> on.",
            "items": {
              "type": "string"
            }
          },
          "maxResults": {
            "title": "Max job postings per board",
            "minimum": 1,
            "maximum": 500,
            "type": "integer",
            "description": "Set how many job postings to request from each board, e.g. <code>20</code> (1–500, values outside are clamped). <b>Per board per search, not in total</b>: 4 boards × 20 = up to 80 rows per search; each search term × location, search URL and ATS company has its own cap. Billed per delivered row <i>after</i> de-duplication. Run time, 1 search, 4 default boards, 1024 MB: 20 per board → 60–80 rows in 30–113 s (12 runs; 60 when one board refused); 50 per board → 134–200 rows in 93–213 s (9 runs).",
            "default": 20
          },
          "isRemote": {
            "title": "Remote jobs only",
            "type": "boolean",
            "description": "Remote roles only. Indeed and Glassdoor apply their own remote filter; LinkedIn ignores it, so every row whose own <code>is_remote</code> is <code>false</code> is dropped before billing (a row with no description carries no evidence and is kept). With <b>Job boards</b> left at its default, the seven remote-only boards join the run: <b>more rows, bigger bill</b>. Re-selecting exactly the four defaults counts as the default; to keep a fixed set, add or drop one board.",
            "default": false
          },
          "onlyNewJobs": {
            "title": "Only new jobs (monitoring mode)",
            "type": "boolean",
            "description": "For scheduled runs: delivers and bills only postings this search has not delivered before. The memory sits in a private key-value store in <i>your</i> account, per search (terms, locations, boards; plus remote, hours and companies when set) for 90 days; the first run delivers everything and starts it. It keys on each posting's URL / listing id, so a job re-listed under a new URL or arriving via another board can appear and bill again (measured: ~2.0% of suppressed rows). (details in the README)",
            "default": false
          },
          "jobType": {
            "title": "Job type",
            "enum": [
              "",
              "fulltime",
              "parttime",
              "internship",
              "contract"
            ],
            "type": "string",
            "description": "Keep one employment type, e.g. <b>Full-time</b>; <b>Any</b> keeps every type. Only Indeed and Glassdoor filter it board-side (LinkedIn ignores it, the keyless API boards have no such filter), so rows whose own <code>job_type</code> contradicts your choice are dropped before billing; rows with no type are kept. Indeed cannot combine it with <b>Posted within (hours)</b> and drops it there (logged); the after-scraping check still runs.",
            "default": ""
          },
          "experienceLevel": {
            "title": "Experience level (best-effort)",
            "type": "array",
            "description": "Keep only these seniority levels, e.g. <b>Entry level</b>; empty keeps every level. Best-effort: the board's own level where it publishes one (LinkedIn with <b>Full LinkedIn job details</b> on, Jobicy, Himalayas, The Muse), else read from the title (e.g. <code>Senior</code> → mid-senior, <code>Junior</code> → entry, <code>Intern</code> → internship, <code>VP</code> → executive). A posting whose level is unknown is <b>kept</b>; filtered rows are never billed. (details in the README)",
            "items": {
              "type": "string",
              "enum": [
                "internship",
                "entry",
                "associate",
                "mid_senior",
                "director",
                "executive"
              ],
              "enumTitles": [
                "Internship",
                "Entry level",
                "Associate",
                "Mid-Senior level",
                "Director",
                "Executive"
              ]
            },
            "default": []
          },
          "requireSalary": {
            "title": "Only jobs with salary",
            "type": "boolean",
            "description": "Keep only job postings that carry a salary figure (<code>salary_min</code> or <code>salary_max</code>). Applied after de-duplication and before billing, so rows without a salary are never charged; Glassdoor and Indeed publish salary most often, LinkedIn rarely.",
            "default": false
          },
          "hoursOld": {
            "title": "Posted within (hours)",
            "minimum": 1,
            "type": "integer",
            "description": "Ask the boards for postings from the last N hours, e.g. <code>168</code> = last week, <code>24</code> = last day. Board-side, so it cannot combine with <b>Easy Apply only</b> on LinkedIn/Indeed or with job type / remote on Indeed: the clashing option is dropped for that board and logged. Above 8760 (one year) it behaves like empty and your other board-side filters are kept. Empty = all ages; <b>Max posting age (days)</b> never clashes."
          },
          "maxAgeDays": {
            "title": "Max posting age (days)",
            "minimum": 1,
            "type": "integer",
            "description": "Drop job postings older than N days, e.g. <code>7</code> for the last week. Applied by the Actor after scraping and before billing, so filtered rows are never charged; unlike <b>Posted within (hours)</b> it works on every board and never clashes with another filter. Job postings the board published without a date are kept; empty keeps everything. Any number you type is applied literally — <code>400</code> means 400 days."
          },
          "targetCompanies": {
            "title": "Only these companies",
            "type": "array",
            "description": "Keep <b>only</b> job postings from these employers, e.g. <code>Deloitte</code> — everything else is dropped, which is how you watch who a competitor is hiring. Names are normalized the way de-duplication does them (<code>Google</code> also matches <code>Google LLC</code>, and <code>Amazon</code> keeps <code>Amazon Web Services</code> but not <code>Amazonia</code>); applied after de-duplication and before billing, so dropped rows are never charged. Leave empty to keep every company.",
            "default": [],
            "items": {
              "type": "string"
            }
          },
          "excludeCompanies": {
            "title": "Exclude companies",
            "type": "array",
            "description": "Drop these employers, e.g. a staffing agency or your own company. Case-insensitive and legal suffixes are ignored, so <code>Wipro</code> also excludes <code>Wipro Limited</code> and <code>Wipro Technologies</code> (same rule as <b>Only these employers</b>, and <code>Wiprox</code> is left alone); filtered job postings are never charged.",
            "default": [],
            "items": {
              "type": "string"
            }
          },
          "excludeTitleKeywords": {
            "title": "Exclude title keywords",
            "type": "array",
            "description": "Drop job postings whose title contains any of these words or phrases, e.g. <code>senior</code>, <code>intern</code>, <code>clearance</code>. Case-insensitive substring match against the title only (not the description), and filtered job postings are never charged.",
            "default": [],
            "items": {
              "type": "string"
            }
          },
          "requireTitleKeywords": {
            "title": "Require title keywords",
            "type": "array",
            "description": "Keep only postings whose title contains <b>at least one</b> of these words or phrases, e.g. <code>intern</code>. Case-insensitive substring match on the title only, the mirror of <b>Exclude title keywords</b>. Dropped rows are never billed and are counted in <code>RUN_SUMMARY.filter_removed.requireTitleKeywords</code>. Not part of the <b>Only new jobs</b> memory: adding or removing it on a schedule never re-delivers old rows.",
            "default": [],
            "items": {
              "type": "string"
            }
          },
          "excludeCities": {
            "title": "Exclude cities",
            "type": "array",
            "description": "Drop job postings whose location mentions any of these places, e.g. <code>San Francisco</code> or <code>Remote</code>. Whole-word, case-insensitive match against the location text exactly as the board published it — <code>Dallas</code> drops <code>Dallas, TX</code> while <code>Dall</code> drops nothing. Best-effort, because boards format locations inconsistently; filtered job postings are never charged.",
            "default": [],
            "items": {
              "type": "string"
            }
          },
          "excludeAgencies": {
            "title": "Exclude staffing agencies & recruiters",
            "type": "boolean",
            "description": "Drop job postings whose <b>company name</b> looks like a staffing agency, recruiter or body shop (staffing, recruit*, headhunt*, talent*, manpower, placement*, consultanc*, workforce, <code>HR solutions</code>…). Heuristic by design — it reads the company name only, so a neutrally-named re-poster slips through and a genuine employer called <code>Workforce</code> is dropped; use <b>Exclude companies</b> for exact control. Filtered job postings are never charged.",
            "default": false
          },
          "excludeClosed": {
            "title": "Exclude closed LinkedIn postings",
            "type": "boolean",
            "description": "Drop LinkedIn job postings whose job page shows <b>No longer accepting applications</b>. Read from the job page the run already fetches when <b>Full LinkedIn job details</b> is on — no extra request. Off by default: closed postings are then delivered with <code>is_closed: true</code> and counted in <code>RUN_SUMMARY.linkedin_closed_rows</code>. LinkedIn only; other boards publish no closed signal. Filtered job postings are never charged.",
            "default": false
          },
          "strictKeywordMatch": {
            "title": "Only job postings that mention my search term",
            "type": "boolean",
            "description": "Drop postings whose title and description never mention your search words; off by default, because some searches want loosely related roles. Turn it on for a narrow role: LinkedIn never answers \"nothing matched\" and fills the page with loosely related jobs, which you would pay for. It can only <b>lower</b> the bill. Either way <code>RUN_SUMMARY.rows_not_mentioning_search_term</code> counts those rows per board.",
            "default": false
          },
          "descriptionFormat": {
            "title": "Description format",
            "enum": [
              "markdown",
              "html"
            ],
            "type": "string",
            "description": "Choose the format of the <code>description</code> column. Markdown is the best input for LLMs and spreadsheets; HTML keeps the board's original markup.",
            "default": "markdown"
          },
          "descriptionHtml": {
            "title": "Raw HTML description column",
            "type": "boolean",
            "description": "Add a <code>description_html</code> column holding the description exactly as the board published it, next to the normal <code>description</code> in your chosen format — same run, no extra requests, no extra cost per job posting. Use the HTML for original formatting (links, lists, headings) and the Markdown for LLMs and spreadsheets; off by default because HTML roughly doubles dataset size.",
            "default": false
          },
          "includeCompanyDetails": {
            "title": "Company details block",
            "type": "boolean",
            "description": "No effect, kept for compatibility: since v0.1.48 the whole company block ships on <b>every</b> run, and the log says so when you set this. What a board does not publish stays null. Which board fills which company field, with measured fill rates, is in the README.",
            "default": false
          },
          "resumeKeywords": {
            "title": "Resume keywords (scoring only)",
            "type": "array",
            "description": "Score every posting against your skills, e.g. <code>Python</code>, <code>SOC 2</code>: <code>matched_keywords</code> and <code>keyword_match_percent</code> (0–100) then score against this list instead of your search terms (both columns are filled either way). Case-insensitive substring match, so <code>c++</code>, <code>.NET</code> and <code>node.js</code> work as written. It <b>never</b> removes a posting or changes billing; pairs best with <b>Sort order</b> = Relevance.",
            "default": [],
            "items": {
              "type": "string"
            }
          },
          "sortBy": {
            "title": "Sort order",
            "enum": [
              "",
              "relevance",
              "date_desc",
              "salary_desc"
            ],
            "type": "string",
            "description": "Choose the order of the final, de-duplicated job postings, e.g. <b>Newest first</b>. Applied before the charge cap, so a truncated run keeps the job postings you ranked highest. <b>Relevance</b> means best keyword match first (your <b>Resume keywords</b> when given, otherwise your search terms), then job postings found on the most boards, then newest; rows missing the chosen key (no date, no salary) always sort last, and <b>Board order</b> keeps the original behaviour.",
            "default": ""
          },
          "enforceAnnualSalary": {
            "title": "Annual salary normalization",
            "type": "boolean",
            "description": "Convert hourly and monthly salaries into an annual figure in <code>salary_min</code>/<code>salary_max</code> where the board gave enough to do it. You rarely need this: <code>salary_min_annual</code> and <code>salary_max_annual</code> are computed on every row regardless, and this switch is what rewrites the raw columns too.",
            "default": false
          },
          "countryIndeed": {
            "title": "Indeed/Glassdoor country",
            "type": "string",
            "description": "Which country's Indeed and Glassdoor site to query, e.g. <code>usa</code>, <code>uk</code>, <code>canada</code>, <code>india</code>, <code>germany</code>; other boards read the country from your location. Usually leave it: a location naming a country (<code>Berlin, Germany</code>) or a non-US <b>City (quick pick)</b> points Indeed there for you, and a value typed here always wins. A spelling the Actor does not recognise falls back to <code>usa</code> with a log note instead of failing the run.",
            "default": "usa"
          },
          "linkedinFetchDescription": {
            "title": "Full LinkedIn job details",
            "type": "boolean",
            "description": "OFF skips LinkedIn job pages: no <code>description, job_type, job_level, company_industry, company_logo, emails, applicants, applicants_is_bound, is_closed, company_linkedin_id</code> or page-only pay from LinkedIn; <code>is_remote</code> ignores the description; isRemote/jobType/excludeClosed keep LinkedIn rows they cannot judge. Same price per row. Run time, default search, 1024 MB: OFF 13–18 s (5 runs), ON 30–113 s (12 runs). OFF also skips BambooHR dates and BambooHR/Workable descriptions.",
            "default": true
          },
          "linkedinCompanyIds": {
            "title": "LinkedIn company IDs",
            "type": "array",
            "description": "Restrict LinkedIn job postings to these numeric company IDs, e.g. <code>1441</code> — copy them from the <code>company_linkedin_id</code> column of a previous run, or from the <code>f_C</code> parameter of a LinkedIn search URL. LinkedIn only; every other board ignores it.",
            "default": [],
            "items": {
              "type": "string"
            }
          },
          "distance": {
            "title": "Distance (miles)",
            "minimum": 0,
            "type": "integer",
            "description": "Set the search radius around the location in miles, e.g. <code>25</code>. LinkedIn and Indeed honor it; Glassdoor and the API boards ignore it, and it does nothing at all without a location."
          },
          "easyApply": {
            "title": "Easy Apply only",
            "type": "boolean",
            "description": "Keep only direct/easy-apply job postings on LinkedIn and Indeed; the other boards ignore it. Cannot be combined with <b>Posted within (hours)</b> on those two boards — when both are set, this one is dropped for them and the log says so.",
            "default": false
          },
          "offset": {
            "title": "Offset",
            "minimum": 0,
            "type": "integer",
            "description": "Skip the first N job postings on each board, e.g. <code>50</code> to page past a run you already have. Combine with <b>Max job postings per board</b> to walk a large search in chunks. LinkedIn, Indeed and Glassdoor page server-side; the five API boards have no paging of their own, so the Actor fetches N extra job postings there and hands you the tail. Either way boards apply it to their own ordering, so it is not a stable cursor — a posting added between two runs can shift the window."
          },
          "googleSearchTerm": {
            "title": "Google Jobs query",
            "type": "string",
            "description": "Enter a full Google Jobs search string, e.g. <code>software engineer jobs near New York since yesterday</code>. Leave empty and one is built from your search term plus location — and note Google Jobs is blocked at the source right now, so this changes nothing today."
          },
          "proxyConfiguration": {
            "title": "Proxy configuration",
            "type": "object",
            "description": "Keep the default datacenter proxy: measured 2026-08-11 on one search, it returned 52 rows in 50 s against 54 rows in 67 s on residential. Switch to RESIDENTIAL only if Glassdoor starts coming back short. No proxy at all is the worst option: Indeed and Glassdoor time out, so you get LinkedIn only. The proxy choice does not change the per-row price.",
            "default": {
              "useApifyProxy": true
            }
          },
          "userAgent": {
            "title": "User agent",
            "type": "string",
            "description": "Send a custom <code>User-Agent</code> header instead of the built-in one, e.g. a current desktop Chrome string. Leave empty unless a board is blocking the default."
          },
          "caCert": {
            "title": "CA certificate",
            "type": "string",
            "description": "Point to a custom CA certificate, by path or by contents — only needed when your own proxy terminates TLS with a private root. Leave empty for Apify Proxy."
          },
          "webhookUrl": {
            "title": "Alert webhook URL (Slack, Discord, n8n, Make, Zapier…)",
            "type": "string",
            "description": "Optional. When a run delivers at least one row, it POSTs a digest here: a Slack or 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 job alerts. Best-effort: a webhook failure is reported in the status message 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
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}