{
  "openapi": "3.0.1",
  "info": {
    "title": "Hiring Signals API — Open Roles & Hiring Surge by Company",
    "description": "Turn a list of companies, ATS boards or a preset into one row per company per run: open roles now, roles opened and closed since your last run, breakdowns by department, location and seniority, remote and salary-disclosure share, top titles and a hiring-surge flag. No API key.",
    "version": "0.1",
    "x-build-id": "LhqOpACufgh9swSjW"
  },
  "servers": [
    {
      "url": "https://api.apify.com/v2"
    }
  ],
  "paths": {
    "/acts/insight.solutions~hiring-signals-api/run-sync-get-dataset-items": {
      "post": {
        "operationId": "run-sync-get-dataset-items-insight.solutions-hiring-signals-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/insight.solutions~hiring-signals-api/runs": {
      "post": {
        "operationId": "runs-sync-insight.solutions-hiring-signals-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/insight.solutions~hiring-signals-api/run-sync": {
      "post": {
        "operationId": "run-sync-insight.solutions-hiring-signals-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",
        "required": [
          "companies"
        ],
        "properties": {
          "companies": {
            "title": "Companies",
            "type": "array",
            "description": "One per line: a company domain (`stripe.com`), a board as `ats:slug` (`greenhouse:stripe`), a career-page URL, or `preset:devtools` / `preset:fintech` / `preset:ai-labs` / `preset:yc-top`. A domain is resolved to its board without a search engine; when it cannot be, you get a free diagnostic listing everything that was tried. The same company named twice is read and billed once.",
            "items": {
              "type": "string"
            }
          },
          "mode": {
            "title": "Mode",
            "enum": [
              "monitor",
              "snapshot"
            ],
            "type": "string",
            "description": "`monitor` diffs every company against the previous run and keeps 90 days of history, so new, closed and changed roles and the hiring surge are filled in. `snapshot` is a one-off: no state, no diff, every company charged. Use snapshot for a diligence pass, monitor on a schedule.",
            "default": "monitor"
          },
          "firstRunBehavior": {
            "title": "First run of a monitored company",
            "enum": [
              "baseline-only",
              "emit-all"
            ],
            "type": "string",
            "description": "`baseline-only` records the baseline on a company's first monitored run and returns its row with every diff field null — and charges nothing for it. `emit-all` returns the full row on the first run and charges it, exactly as snapshot mode would. Only matters in monitor mode.",
            "default": "baseline-only"
          },
          "emitRoles": {
            "title": "Also return one row per job posting",
            "type": "boolean",
            "description": "Adds a `role` row per posting on top of each company row — title, department, location, salary, apply URL, never a description. Charged at $0.001 per role row, the same price as the Career Site Jobs API, which is what these rows are. Off by default; `newTitles` on the company row is free.",
            "default": false
          },
          "roleScope": {
            "title": "Which postings to return as role rows",
            "enum": [
              "new",
              "changed",
              "all"
            ],
            "type": "string",
            "description": "Only used when role rows are on. `new` returns roles that appeared since the previous run, `changed` adds edited ones with `changedFields` and `previousValues`, `all` returns every open role. In snapshot mode and on a first run there is no previous run, so only `all` returns rows.",
            "default": "new"
          },
          "webhookUrl": {
            "title": "Webhook URL (optional)",
            "type": "string",
            "description": "One HTTP(S) POST when the run finishes, carrying a digest of the companies that moved: top 25 by new roles, surging first. Free, 10-second timeout, one retry, 64 KB cap, redirects off the host never followed. Treated as a secret — only its host is ever logged. Leave empty for no webhook."
          },
          "titleFilter": {
            "title": "Job title contains any of",
            "type": "array",
            "description": "Count only roles whose title contains one of these, case-insensitively. Filters change what the aggregate counts — `openRoles` becomes \"open roles matching the filter\" — and every row records `filtersApplied` so a number is never read out of context. Filtering never changes the price.",
            "default": [],
            "items": {
              "type": "string"
            }
          },
          "titleExclude": {
            "title": "Job title must not contain",
            "type": "array",
            "description": "Leave out roles whose title contains any of these, case-insensitively. Applied after the include list, so a role matching both is left out. Useful for `[\"intern\", \"contract\"]` when you only want permanent hiring counted.",
            "default": [],
            "items": {
              "type": "string"
            }
          },
          "seniorityLevels": {
            "title": "Seniority levels",
            "type": "array",
            "description": "Count only these bands, read from the title (no ATS publishes a level). `mid` means a title with no seniority word at all, `lead` also covers Staff, `executive` also covers VP. The same vocabulary as the `bySeniority` breakdown, so the two always agree. Leave empty for every level.",
            "items": {
              "type": "string",
              "enum": [
                "intern",
                "junior",
                "mid",
                "senior",
                "lead",
                "principal",
                "manager",
                "director",
                "executive"
              ],
              "enumTitles": [
                "Intern",
                "Junior / entry level",
                "Mid level (no seniority word in the title)",
                "Senior",
                "Lead / staff",
                "Principal",
                "Manager",
                "Director / head of",
                "Executive / VP"
              ]
            },
            "default": []
          },
          "employmentTypes": {
            "title": "Employment types",
            "type": "array",
            "description": "Count only these employment types. Roles whose ATS publishes no type are left out when this is set, because there is nothing to match them against — Greenhouse, for one, never publishes it. Leave empty to count every role.",
            "items": {
              "type": "string",
              "enum": [
                "FullTime",
                "PartTime",
                "Contract",
                "Temporary",
                "Internship",
                "Volunteer",
                "Other"
              ],
              "enumTitles": [
                "Full time",
                "Part time",
                "Contract / freelance",
                "Temporary / fixed term",
                "Internship",
                "Volunteer",
                "Other"
              ]
            },
            "default": []
          },
          "workplaceTypes": {
            "title": "Workplace types",
            "type": "array",
            "description": "Count only remote, hybrid or on-site roles. A role counts as remote when the ATS says so or its location text does. Roles the ATS says nothing about are left out when this is set — and a `remoteShare` of 1.0 under `remote` is a tautology, which is why the row says the filter was on.",
            "items": {
              "type": "string",
              "enum": [
                "remote",
                "hybrid",
                "onsite"
              ],
              "enumTitles": [
                "Remote",
                "Hybrid",
                "On-site"
              ]
            },
            "default": []
          },
          "countryCodes": {
            "title": "Country codes",
            "type": "array",
            "description": "Count only roles in these countries, as ISO 3166-1 alpha-2 codes such as `US`, `GB`, `DE`. Country names the ATS wrote out are matched too, and a US state or Canadian province implies its country. Leave empty for every country.",
            "default": [],
            "items": {
              "type": "string"
            }
          },
          "locationFilter": {
            "title": "Location contains any of",
            "type": "array",
            "description": "Count only roles whose location text contains one of these strings, case-insensitively — for cities and regions a country code cannot express, such as `Berlin`, `Bay Area` or `EMEA`. Leave empty for every location.",
            "default": [],
            "items": {
              "type": "string"
            }
          },
          "hasSalary": {
            "title": "Only roles with a published salary",
            "type": "boolean",
            "description": "Count only roles carrying a structured pay range from the ATS — never one parsed out of prose. Most roles publish none, so expect `openRoles` to fall sharply. For the share of a board that publishes pay, leave this off and read `salaryDisclosedShare`.",
            "default": false
          },
          "salaryFloor": {
            "title": "Minimum salary",
            "minimum": 0,
            "type": "integer",
            "description": "Count only roles whose published pay reaches this number, compared against the top of the range in the role's own currency and period, with no conversion. Roles with no published pay are left out. Leave at 0 for no floor.",
            "default": 0
          },
          "postedWithinDays": {
            "title": "Posted within the last N days",
            "minimum": 0,
            "maximum": 365,
            "type": "integer",
            "description": "Count only roles first published within this many days. Roles whose ATS publishes no date are kept, so an undated board is never emptied by this filter. Leave at 0 for no age limit.",
            "default": 0
          },
          "atsPlatforms": {
            "title": "Restrict ATS auto-detection",
            "type": "array",
            "description": "Only affects company domains: when set, a domain may only resolve to a board on these platforms, and a registry or cached answer on another platform becomes a free platform-excluded row. Boards you send as ats:slug and preset members are always read. Leave empty to allow all thirteen.",
            "items": {
              "type": "string",
              "enum": [
                "greenhouse",
                "lever",
                "ashby",
                "workable",
                "recruitee",
                "smartrecruiters",
                "teamtailor",
                "personio",
                "workday",
                "breezy",
                "jazzhr",
                "bamboohr",
                "rippling"
              ],
              "enumTitles": [
                "Greenhouse",
                "Lever",
                "Ashby",
                "Workable",
                "Recruitee",
                "SmartRecruiters",
                "Teamtailor",
                "Personio",
                "Workday (beta)",
                "Breezy HR",
                "JazzHR (beta)",
                "BambooHR (beta)",
                "Rippling (beta)"
              ]
            },
            "default": []
          },
          "changedFields": {
            "title": "What counts as a changed role",
            "type": "array",
            "description": "Which fields have to move before a role counts in `changedRoles` (monitor mode). Title, location and salary by default; department and workplace type are also available. Descriptions are never tracked, and a bare updatedAt bump is never a change.",
            "items": {
              "type": "string",
              "enum": [
                "title",
                "location",
                "salary",
                "department",
                "workplaceType"
              ],
              "enumTitles": [
                "Title",
                "Location",
                "Salary",
                "Department",
                "Workplace type"
              ]
            },
            "default": [
              "title",
              "location",
              "salary"
            ]
          },
          "maxRolesPerBoard": {
            "title": "Max roles per board",
            "minimum": 1,
            "maximum": 20000,
            "type": "integer",
            "description": "A board that fills this ceiling has its diff suspended and its row flagged `truncated` with `openRoles` null and nothing charged — roles we did not read are never reported as closed. Keep it above your largest board; 2000 covers almost every company.",
            "default": 2000
          },
          "maxCompanies": {
            "title": "Max companies per run",
            "minimum": 1,
            "maximum": 2000,
            "type": "integer",
            "description": "A ceiling on distinct companies read in one run, after presets are expanded and duplicates folded. Entries past it get a free `max-companies` row and are not read or charged. It bounds the bill of a run you did not size yourself.",
            "default": 500
          },
          "stateStoreName": {
            "title": "State store name",
            "type": "string",
            "description": "The named key-value store holding each company's previous snapshot, its 90-day history and the domain-to-board cache, in monitor mode. One store per watchlist: name your own to keep separate watchlists apart. Two runs sharing one store never run at once — the second stops with a free row.",
            "default": "hiring-signals-api-state"
          },
          "requestTimeoutSecs": {
            "title": "Request timeout (seconds)",
            "minimum": 5,
            "maximum": 120,
            "type": "integer",
            "description": "Per-request timeout for board reads. A URL is abandoned once its attempts have used twice this, or 40 seconds, whichever is longer. Raise it only for very large SmartRecruiters or Workday boards.",
            "default": 20
          },
          "maxRunSecs": {
            "title": "Max run time (seconds)",
            "minimum": 60,
            "maximum": 3600,
            "type": "integer",
            "description": "Wall-clock budget for the whole run. Resolving domains may use up to three quarters of it; the rest is kept for reading boards. Companies not reached get a free deadline row, keep their snapshots and are never charged.",
            "default": 240
          },
          "maxConcurrency": {
            "title": "Max companies in flight",
            "minimum": 1,
            "maximum": 12,
            "type": "integer",
            "description": "How many companies are resolved and read at the same time. Each worker keeps its own proxy session for careers pages, and no more than one request at a time ever goes to a single host. Six suits almost every watchlist.",
            "default": 6
          },
          "proxyConfiguration": {
            "title": "Proxy configuration",
            "type": "object",
            "description": "Used only for the company careers pages read while resolving a domain. The ATS feeds themselves are public syndication endpoints and are always read directly. The Apify datacenter proxy is the default; switch to residential only if careers pages refuse it.",
            "default": {
              "useApifyProxy": true
            }
          }
        }
      },
      "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
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}