{
  "openapi": "3.0.1",
  "info": {
    "title": "Open ATS Jobs Feed — Greenhouse, Ashby, Lever & 3 More",
    "description": "18,164 verified company boards on Greenhouse, Ashby, Lever, Breezy, Recruitee and Teamtailor, via their official public APIs. Normalised postings with salary, seniority and workplace — or one row per company: who is ramping and which functions just opened. MLM ads and unpaid listings filtered.",
    "version": "0.1",
    "x-build-id": "A5n7VnKtj6Tj63uTz"
  },
  "servers": [
    {
      "url": "https://api.apify.com/v2"
    }
  ],
  "paths": {
    "/acts/sharp_malachite~open-ats-jobs-feed/run-sync-get-dataset-items": {
      "post": {
        "operationId": "run-sync-get-dataset-items-sharp_malachite-open-ats-jobs-feed",
        "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/sharp_malachite~open-ats-jobs-feed/runs": {
      "post": {
        "operationId": "runs-sync-sharp_malachite-open-ats-jobs-feed",
        "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/sharp_malachite~open-ats-jobs-feed/run-sync": {
      "post": {
        "operationId": "run-sync-sharp_malachite-open-ats-jobs-feed",
        "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": {
          "outputMode": {
            "title": "What to deliver",
            "enum": [
              "postings",
              "signals"
            ],
            "type": "string",
            "description": "Postings: one row per open job. Hiring signals: one row per company — how many roles it opened in the last 7 / 30 / 90 days, how that compares with its own prior pace, which functions it has just opened for the first time, and which technologies it is hiring for. Both come from the same scan, so a signals run reads exactly the same boards and delivers roughly 1/30th of the rows.",
            "default": "postings"
          },
          "signalTypes": {
            "title": "Only these signals",
            "type": "array",
            "description": "Signals mode only. Ramping: 3+ roles opened in the last 30 days, at 2x or more the pace of the 60 days before that. New board: nothing on the board is older than 60 days. Steady: hiring, but not accelerating. Quiet: open roles, none opened in the last 30 days. Leave empty to get every company.",
            "items": {
              "type": "string",
              "enum": [
                "ramping",
                "new_board",
                "steady",
                "quiet",
                "undated"
              ],
              "enumTitles": [
                "Ramping",
                "New board",
                "Steady",
                "Quiet",
                "No dates published"
              ]
            }
          },
          "minOpenPostings": {
            "title": "Minimum open roles per company",
            "minimum": 1,
            "type": "integer",
            "description": "Signals mode only. Companies with fewer open roles than this (after your filters) are skipped entirely, so you are not billed for one-role boards.",
            "default": 1
          },
          "providers": {
            "title": "ATS providers",
            "type": "array",
            "description": "Which applicant tracking systems to read. Greenhouse, Ashby, Breezy, Recruitee and Teamtailor are fast and are the default — every one of them was probed across its whole harvested token list at concurrency 8 without being throttled into uselessness (Recruitee refused 5 of 3,554 and Teamtailor 0 of 3,175; 4 of Recruitee's 5 turned out to be live boards when re-asked one at a time). Lever is fetched at 1 request per second because api.lever.co asks for that in its robots.txt, so a large Lever run is slow by design. Workable is off by default for a different reason: its robots.txt allows everything, but apply.workable.com sits behind Cloudflare bot management, which begins answering 429 to every request after a few hundred in quick succession and clears again once you slow down. A large Workable run therefore returns blocked boards rather than jobs unless it is paced, and it has no boards in the bundled index yet — select it only together with an explicit company list. Measured 2026-09-03.",
            "items": {
              "type": "string",
              "enum": [
                "greenhouse",
                "ashby",
                "breezy",
                "recruitee",
                "teamtailor",
                "workable",
                "lever"
              ],
              "enumTitles": [
                "Greenhouse",
                "Ashby",
                "Breezy",
                "Recruitee",
                "Teamtailor",
                "Workable (no bundled boards — needs an explicit company list)",
                "Lever (slow — 1 req/s)"
              ]
            },
            "default": [
              "greenhouse",
              "ashby",
              "breezy",
              "recruitee",
              "teamtailor"
            ]
          },
          "keywords": {
            "title": "Keywords",
            "type": "array",
            "description": "Keep a posting if any keyword appears in its title, department, team, or description. Leave empty to keep everything.",
            "items": {
              "type": "string"
            }
          },
          "location": {
            "title": "Location contains",
            "type": "string",
            "description": "Substring match on the posting's location string, e.g. \"Berlin\", \"United Kingdom\", \"New York\"."
          },
          "workplace": {
            "title": "Workplace type",
            "type": "array",
            "description": "Remote / hybrid / onsite, derived from the vendor's own workplace field where it exists and from the location text otherwise.",
            "items": {
              "type": "string",
              "enum": [
                "remote",
                "hybrid",
                "onsite"
              ],
              "enumTitles": [
                "Remote",
                "Hybrid",
                "Onsite"
              ]
            }
          },
          "seniority": {
            "title": "Seniority",
            "type": "array",
            "description": "Inferred from the job title.",
            "items": {
              "type": "string",
              "enum": [
                "intern",
                "junior",
                "mid",
                "senior",
                "principal",
                "executive"
              ],
              "enumTitles": [
                "Intern",
                "Junior",
                "Mid",
                "Senior",
                "Principal / Staff",
                "Executive"
              ]
            }
          },
          "department": {
            "title": "Department contains",
            "type": "string",
            "description": "Substring match on the department name, e.g. \"Engineering\", \"Sales\"."
          },
          "postedSince": {
            "title": "Only postings updated since",
            "type": "string",
            "description": "YYYY-MM-DD. This is the delta mode: poll daily and pay for what changed instead of re-downloading the world."
          },
          "withSalaryOnly": {
            "title": "Only postings with a parsed salary range",
            "type": "boolean",
            "description": "Salary is parsed out of free text and is left null unless the range is unambiguous. A wrong salary is worse than an absent one.",
            "default": false
          },
          "excludeRecruitmentAds": {
            "title": "Exclude suspect recruitment ads",
            "type": "boolean",
            "description": "On by default. Removes open-ended commission-only / MLM recruitment copy — \"be your own boss\", \"tired of your income being capped?\", \"work from home – client benefits representative\" — which sits on real Greenhouse, Ashby and Lever boards and is not an opening. Measured on 2026-09-03: 1,411 of 121,050 titles read across 500 boards, 1.17% of what was read. The share is not the point — the concentration is: only 2 of those 500 boards carry any of it, and one of them, lever/globalelitecareers, is 1,380 of its 1,752 postings. On almost every board this filter does nothing; on that one it is the difference between a usable run and 1,380 rows of pitch. RUN_STATS.recruitment_ads_excluded reports how many rows it removed on your run whether it is on or off. Turn it off to receive the corpus unfiltered.",
            "default": true
          },
          "excludeVolunteerListings": {
            "title": "Exclude volunteer and unpaid listings",
            "type": "boolean",
            "description": "On by default. Removes listings that are not paid work — \"Hospice Volunteer (Unpaid)\", \"Private Equity Event Volunteer\", \"Event Assistant (volunteer)\". Measured on 2026-09-03: 445 of 121,050 titles read, on 8 of 500 boards, mostly conference organisers staffing events with unpaid help — greenhouse/privateequityinsights is 113 of 1,159 postings. Paid jobs that manage volunteers (\"Volunteer Services Manager\", \"Director of Volunteer Engagement\") are deliberately kept. RUN_STATS.volunteer_listings_excluded reports the count whether this is on or off. Turn it off if you want unpaid roles in the feed — nonprofit boards usually do.",
            "default": true
          },
          "dedupe": {
            "title": "Collapse duplicate postings (same title, same stated location)",
            "type": "boolean",
            "description": "Off by default. Keeps one row when a board posts the same title at the same stated location more than once, and records how many copies were collapsed in the row's `duplicates_merged` field. Same title at a DIFFERENT location is never touched — a retailer posting \"Sales Associate\" in seventy-six towns is filling seventy-six real openings, and the store is in the location field, not the title. Postings with no stated location are never collapsed either: unstated is not the same as same-place. Corpus-wide this removes 3.03% of open postings (95% CI 2.86-3.22%), measured on 2026-09-03 by reading 1,317 boards live — 166,320 postings, 57% of the corpus — drawn by board size, never by how much a board repeats itself. Read the shape before you decide: the rate falls off a cliff with board size (500+ postings 7.60%, 100-499 2.87%, 30-99 1.64%, 10-29 0.90%, 3-9 zero), and it is concentrated — only 34% of boards carry a single duplicate, and the worst 10 account for 47% of them. If you pull small or mid-size boards it has nothing to find. It is also a lower bound: we strip noise words but resolve nothing, so \"Leeds\" and \"Leeds, UK\" stay two places. Why this is off while the other two Quality filters are on: they remove rows that are not paid openings at all, whereas three requisitions for three headcount at one site look exactly like three copies of one job and the ATS does not publish headcount. Dropping a real opening is worse than carrying a duplicate, so the choice is yours. RUN_STATS.duplicates_merged reports the count whether this is on or off, so you can see what it would take before turning it on.",
            "default": false
          },
          "companies": {
            "title": "Specific company boards",
            "type": "array",
            "description": "Board tokens, optionally prefixed with the provider — \"greenhouse:stripe\", \"ashby:ramp\", or a bare \"stripe\", which is sent to whichever provider the bundled roster has it on — and only to every selected provider if the roster has never seen it. Overrides the bundled index entirely.",
            "items": {
              "type": "string"
            }
          },
          "maxCompaniesPerProvider": {
            "title": "Max company boards per provider",
            "minimum": 1,
            "maximum": 12000,
            "type": "integer",
            "description": "Applied per provider, not per run — with two providers selected this is up to 500 boards, and it is also the number you are billed 'board scanned' events against. Boards are ordered by posting count, largest first, so a capped run gets the biggest boards rather than an alphabetical slice. Raise it to sweep everything.",
            "default": 250
          },
          "maxItems": {
            "title": "Max rows",
            "minimum": 1,
            "type": "integer",
            "description": "Hard cap on dataset rows — postings in postings mode, companies in signals mode. The run stops as soon as it is reached. The cap is split evenly across the providers you selected, so a two-provider run returns both rather than filling up on the first one. Raise it for a full harvest; the default is sized to be a cheap look at the feed.",
            "default": 1000
          },
          "includeDescription": {
            "title": "Include full job description",
            "type": "boolean",
            "description": "Postings mode: adds the plain-text description to every record, roughly 10x the dataset size. Signals mode: the description is never delivered, but turning this on widens technology detection past the job title — more matches, and some of them from a stack mentioned only in a benefits paragraph.",
            "default": false
          },
          "includeEmptyBoards": {
            "title": "Also fetch boards that were empty at index time",
            "type": "boolean",
            "description": "1,268 boards existed but had nothing open when we last swept. They may have postings now.",
            "default": false
          },
          "includeUnverifiedLever": {
            "title": "Also try unverified Lever boards",
            "type": "boolean",
            "description": "3,961 harvested Lever tokens have not been probed yet — unprobed, not dead. Checking them costs 1 second each.",
            "default": false
          }
        }
      },
      "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
                  }
                }
              },
              "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
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}