{
  "openapi": "3.0.1",
  "info": {
    "title": "Job Board Scraper & API — LinkedIn, Indeed, Glassdoor + 29 More",
    "description": "Full job descriptions and USD salaries on every row, from LinkedIn, Indeed, Glassdoor and 29 more sources, including 2,335 employers' own career sites on 17 ATS platforms, in one deduplicated dataset. Monitor mode for daily feeds of new postings, MCP-ready for AI agents.",
    "version": "1.0",
    "x-build-id": "glzHC0WAJtxd4BJCQ"
  },
  "servers": [
    {
      "url": "https://api.apify.com/v2"
    }
  ],
  "paths": {
    "/acts/spool~job-board-api/run-sync-get-dataset-items": {
      "post": {
        "operationId": "run-sync-get-dataset-items-spool-job-board-api",
        "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/spool~job-board-api/runs": {
      "post": {
        "operationId": "runs-sync-spool-job-board-api",
        "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/spool~job-board-api/run-sync": {
      "post": {
        "operationId": "run-sync-spool-job-board-api",
        "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": {
          "searchTerms": {
            "title": "Job titles or keywords",
            "type": "array",
            "description": "Up to five, one per line, searched together and merged — `software engineer`, `data analyst`, `account executive`. Related titles are added only when your own words leave the run short of the result count, and a row found that way must carry the related title itself.\n\nLeave empty when you name companies below: then their whole boards are read.",
            "items": {
              "type": "string"
            }
          },
          "location": {
            "title": "Location",
            "type": "string",
            "description": "City, region or country — `New York, NY`, `London`, `Germany`, or `Remote`. Several places, one per line, are each searched and merged. Boards answer a city with its 25-mile area; every row says `inSearchedCity` so you can keep the city proper. LinkedIn is global; the country below picks the Indeed and Glassdoor site."
          },
          "remoteOnly": {
            "title": "Remote only",
            "type": "boolean",
            "description": "Passed to each board's own remote filter. Every row also carries `isRemote` and `locationType`, judged from the title, location and text, which catches postings the boards mislabel.",
            "default": false
          },
          "country": {
            "title": "Country (Indeed and Glassdoor site)",
            "type": "string",
            "description": "Which national Indeed and Glassdoor site to search: `usa`, `uk`, `canada`, `australia`, `germany`, `france`, `india`, `singapore`, `uae`, `netherlands`, `spain`, `brazil`, `mexico`, `japan` and 50 more, as Indeed names them.",
            "default": "usa"
          },
          "results": {
            "title": "Results per run",
            "minimum": 20,
            "maximum": 10000,
            "type": "integer",
            "description": "How many jobs the run delivers: the boards are asked for enough to reach this number after duplicates are merged, and delivery stops at it. 20 to 10,000. The default 120 is about 20 rows from each source and costs about $0.06; set 500 or 1,000 for the whole market of a search. You are charged per row delivered; duplicates and filtered rows cost nothing. Memory: 2 GB covers about 6,000 rows; above that, start the run with 4 GB.",
            "default": 120
          },
          "companies": {
            "title": "Companies — straight from their own job boards",
            "type": "array",
            "description": "Employers to read directly from their own board: a name (`Stripe`), a domain (`ramp.com`), or a board URL. Greenhouse, Ashby, Lever, SmartRecruiters, Rippling, Workday, Oracle, SuccessFactors, Phenom, Eightfold and nine more platforms are read; a name that is not matched directly is found through the company's careers page. With job titles set, only matching roles are kept; without them, the whole board.",
            "items": {
              "type": "string"
            }
          },
          "searchUrls": {
            "title": "Or paste search URLs",
            "type": "array",
            "description": "LinkedIn, Indeed or Glassdoor search pages, one per line. Each URL replaces the search term, location and board for the board it came from: keywords, place, posted-within, remote, job type, seniority, radius and page offset are read from it. A URL that cannot be read is named in RUN_SUMMARY.searchUrls and skipped, never guessed.",
            "items": {
              "type": "string"
            }
          },
          "searchEmployerBoards": {
            "title": "Also search N verified employer boards",
            "minimum": 0,
            "maximum": 2000,
            "type": "integer",
            "description": "Ask the N largest boards in the bundled list of 2,335 verified employers (Greenhouse, Ashby, Lever, Workday, Oracle, SuccessFactors, Phenom and more; 353,000 open roles) for your terms, straight from the employer: postings no job board carries, with the employer's own salary and text. Default 600, up to 2,000; 0 turns it off.",
            "default": 600
          },
          "boards": {
            "title": "Job boards and sources",
            "type": "array",
            "description": "Indeed (salary and description on every row), LinkedIn (global), Glassdoor (salaries, company ratings) and The Muse are on by default. Add Naukri (India), Bayt (Middle East), BDJobs (Bangladesh), Welcome to the Jungle (Europe), the free remote feeds (Remotive, RemoteOK, Arbeitnow, Jobicy, Himalayas, Working Nomads, We Work Remotely), Hacker News \"Who is hiring?\" and the college jobs list. A remote search adds the remote feeds on its own. Rows from every source share one shape; the same posting on two boards is one row with `alsoOn`.",
            "items": {
              "type": "string",
              "enum": [
                "indeed",
                "linkedin",
                "glassdoor",
                "muse",
                "naukri",
                "bayt",
                "bdjobs",
                "remotive",
                "remoteok",
                "arbeitnow",
                "jobicy",
                "himalayas",
                "workingnomads",
                "weworkremotely",
                "hackernews",
                "collegejobs",
                "wttj"
              ],
              "enumTitles": [
                "Indeed — salary + description on every row",
                "LinkedIn — global; descriptions via employer boards",
                "Glassdoor — salaries, company ratings",
                "The Muse (keyless, city-aware, full descriptions)",
                "Naukri — India; skills and experience",
                "Bayt — Middle East",
                "BDJobs — Bangladesh",
                "Remotive — remote, free API",
                "RemoteOK — remote, free API, salaries",
                "Arbeitnow — Europe, free API",
                "Jobicy — remote, free API, salaries",
                "Himalayas — remote, 116k+ jobs, free API",
                "Working Nomads — remote, free API",
                "We Work Remotely — remote, RSS",
                "Hacker News: Who is hiring? — monthly thread",
                "College jobs — SWE internships and new-grad roles (speedyapply list, daily)",
                "Welcome to the Jungle — Europe (France, UK, Spain…), salaries, 10k+ jobs"
              ]
            },
            "default": [
              "indeed",
              "linkedin",
              "glassdoor",
              "muse"
            ]
          },
          "postedWithinHours": {
            "title": "Posted within the last N hours",
            "minimum": 1,
            "type": "integer",
            "description": "24 = last day, 168 = last week. **Board quirks:** LinkedIn cannot combine this with Easy Apply; Indeed cannot combine it with job type, remote or Easy Apply — the board silently ignores one of them."
          },
          "jobType": {
            "title": "Job type",
            "enum": [
              "",
              "fulltime",
              "parttime",
              "contract",
              "internship",
              "temporary"
            ],
            "type": "string",
            "description": "Employment type filter.",
            "default": ""
          },
          "experienceLevel": {
            "title": "Experience level",
            "type": "array",
            "description": "Keep only these levels, read from the board's own label where it has one, else from the title (Senior, Principal, Lead; Junior, Graduate, Entry level; Intern; Director; VP, Chief, Head of). A row with no level cue is kept, never dropped. Removed rows are never charged.",
            "items": {
              "type": "string",
              "enum": [
                "junior",
                "mid",
                "senior",
                "manager",
                "director",
                "executive"
              ]
            }
          },
          "requireSalary": {
            "title": "Only jobs that state a salary",
            "type": "boolean",
            "description": "Keep rows with a salary from the board or the employer's ATS. Applied after deduplication and enrichment, so a LinkedIn row whose salary came from Greenhouse is kept.",
            "default": false
          },
          "minSalaryUsd": {
            "title": "Minimum salary (USD, annualised)",
            "type": "integer",
            "description": "Compared against the annualised USD figure, so an hourly US wage and a monthly EUR salary are judged on the same scale."
          },
          "requireTech": {
            "title": "Only jobs mentioning these technologies",
            "type": "array",
            "description": "Keep rows whose text names any of these — `Kubernetes`, `Snowflake`, `Salesforce`, `React`… Spelled as in the output's `tech` field. 190 technologies are recognised.",
            "items": {
              "type": "string"
            }
          },
          "excludeTitleKeywords": {
            "title": "Exclude titles containing",
            "type": "array",
            "description": "Drop jobs whose title contains any of these words or phrases (case-insensitive). Removed rows are never charged.",
            "items": {
              "type": "string"
            }
          },
          "excludeCompanies": {
            "title": "Exclude companies",
            "type": "array",
            "description": "Drop these employers. Names are normalised first, so `Wipro` also drops `Wipro Limited`. Removed rows are never charged.",
            "items": {
              "type": "string"
            }
          },
          "excludeAgencies": {
            "title": "Drop staffing agencies",
            "type": "boolean",
            "description": "Drop rows whose company name reads like a staffing or recruiting agency (staffing, recruit…, headhunt…, talent…, manpower, personnel, placement…, consultanc…, resourcing, workforce…). A heuristic on the name only. Removed rows are never charged.",
            "default": false
          },
          "onlyNew": {
            "title": "Only new jobs since the last run (monitor mode)",
            "type": "boolean",
            "description": "Remember every posting this search has delivered and return only the ones not seen before. Put the run on a schedule — daily, hourly — and you get a feed of new postings; nothing delivered earlier is charged again. The memory is a record per search in a key-value store named `job-board-api-monitor` in **your** account (see *Monitor name*). Postings not seen for 60 days are forgotten, so a role closed and reposted later shows up again.",
            "default": false
          },
          "webhookUrl": {
            "title": "Alert webhook",
            "type": "string",
            "description": "When rows are delivered, POST a digest here: a Slack or Discord incoming webhook gets a short message with the first rows and a link to all of them; any other URL gets the full JSON digest (run and dataset ids and links, counts, the first ten rows). A run that delivers nothing sends nothing, so a scheduled monitor only speaks when there is something new."
          }
        }
      },
      "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
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}