{
  "openapi": "3.0.1",
  "info": {
    "title": "Jobs Feed API - Deduplicated LinkedIn, Indeed & ATS Jobs",
    "description": "Deduplicated job postings from Greenhouse, Lever, Ashby, LinkedIn (public) and Indeed in one normalized schema, with a delta mode that returns only new, changed and removed jobs between runs - guest pages only, no login.",
    "version": "0.7",
    "x-build-id": "qbw2A6sUkXwfLgG8f"
  },
  "servers": [
    {
      "url": "https://api.apify.com/v2"
    }
  ],
  "paths": {
    "/acts/sergeyfaraday~jobs-feed-api/run-sync-get-dataset-items": {
      "post": {
        "operationId": "run-sync-get-dataset-items-sergeyfaraday-jobs-feed-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/sergeyfaraday~jobs-feed-api/runs": {
      "post": {
        "operationId": "runs-sync-sergeyfaraday-jobs-feed-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/sergeyfaraday~jobs-feed-api/run-sync": {
      "post": {
        "operationId": "run-sync-sergeyfaraday-jobs-feed-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": {
          "queries": {
            "title": "Search queries",
            "maxItems": 20,
            "type": "array",
            "description": "Job titles or search words, up to 20. Combined with Companies below. In the API each entry may also be an object {\"q\": \"...\", \"location\": \"...\", \"datePosted\": \"...\"} to scope one query to its own location and freshness window.",
            "items": {
              "type": "string"
            }
          },
          "location": {
            "title": "Location",
            "type": "string",
            "description": "Keep only jobs in this location (e.g. \"Dubai\", \"Berlin\", \"United States\", \"Remote\"). LinkedIn/Indeed searches are scoped server-side by the platform's own geo resolution; ATS board postings are matched by their location text. A posting with no location information cannot confirm the filter and is dropped. Per-query override: pass queries as objects {\"q\": \"...\", \"location\": \"...\", \"datePosted\": \"...\"} in the API."
          },
          "datePosted": {
            "title": "Date posted",
            "enum": [
              "any",
              "24h",
              "3d",
              "7d",
              "14d",
              "30d"
            ],
            "type": "string",
            "description": "Keep only jobs posted within this window - and stop paying to re-scan history: LinkedIn/Indeed searches are narrowed server-side (f_TPR / fromage), ATS postings are cut by their posted date (postings without a date are kept). The API also accepts an integer number of days (1-365). With trackRemovals, a job leaving the window is never mistaken for a removal.",
            "default": "any"
          },
          "companies": {
            "title": "Companies",
            "maxItems": 500,
            "type": "array",
            "description": "Up to 500 entries: `{\"domain\": \"example.com\", \"greenhouseBoard\": \"...\", \"leverSite\": \"...\", \"ashbyBoard\": \"...\"}`. Only `domain` is required - ATS boards are resolved automatically; the optional board slugs override the resolver."
          },
          "sources": {
            "title": "Sources",
            "type": "array",
            "description": "Which sources to scan. Greenhouse/Lever/Ashby read public board APIs (default). Guest sources - no login, no accounts - are listed by how cleanly their published rules permit automated reading: Indeed (the guest result page per query, newest first), Glassdoor (first search page per query and location inside your datePosted window), LinkedIn (guest job pages). Indeed and Glassdoor are read in a real browser: give the run at least 2048 MB of memory or it fails before scanning anything; the first such run on a cold worker adds about 25-30 seconds. Guest sources carry higher operational risk, run through the built-in residential proxy, and can be paused by the operator.",
            "items": {
              "type": "string",
              "enum": [
                "greenhouse",
                "lever",
                "ashby",
                "indeed",
                "glassdoor",
                "linkedin-public"
              ],
              "enumTitles": [
                "Greenhouse",
                "Lever",
                "Ashby",
                "Indeed (guest search, browser)",
                "Glassdoor (guest search, browser)",
                "LinkedIn (public, no login)"
              ]
            },
            "default": [
              "greenhouse",
              "lever",
              "ashby"
            ]
          },
          "maxItems": {
            "title": "Max rows",
            "minimum": 1,
            "maximum": 50000,
            "type": "integer",
            "description": "Caps emitted rows (new + updated combined). Hard limit 50 000. The console prefill is 200 so a first click costs at most about $0.28; the API default is 1000.",
            "default": 1000
          },
          "matchProfile": {
            "title": "Match profile (resume keywords)",
            "type": "object",
            "description": "Score every job against your keywords: {\"keywords\": [{\"keyword\": \"TypeScript\", \"aliases\": [\"TS\"], \"weight\": 2}], \"minMatchScore\": 60}. Rows below minMatchScore are NOT emitted and NOT billed (matchFiltered in the report counts them); minMatchScore null annotates only. Whole-word, case-insensitive; matchScore = matched weights / total weights x 100. The matchBasis field on every row tells you whether the score used the full description or only title + snippet."
          },
          "earlyApplicantsOnly": {
            "title": "Early applicants only",
            "type": "boolean",
            "description": "Keep only jobs whose posting shows the \"Be among the first N applicants\" signal (LinkedIn detail pages). Filtered rows are not emitted and not billed. Needs detailFetch (the signal lives on the posting page).",
            "default": false
          },
          "detailFetch": {
            "title": "Full posting pages",
            "enum": [
              "off",
              "all",
              "selective"
            ],
            "type": "string",
            "description": "Guest sources (LinkedIn) run in list mode by default - full posting pages (complete description, applicant hints) are never fetched implicitly. Each fetched page is billed as one job-detail-fetch event. \"selective\" needs a match profile: the provisional score is computed from title + snippet, so description-only skills can be missed - the threshold trades cost for recall; minMatchScore always applies to the FINAL score computed on the full text.",
            "default": "off"
          },
          "detailFetchMinScore": {
            "title": "Selective fetch threshold",
            "minimum": 0,
            "maximum": 100,
            "type": "integer",
            "description": "Provisional match score (0-100, computed on title + snippet) a posting must reach before its full page is fetched. Only used when detailFetch is \"selective\". A fetched page is billed even when the final score then falls below minMatchScore - you paid to find out.",
            "default": 50
          },
          "dedupTier": {
            "title": "Dedup mode",
            "enum": [
              "standard",
              "strict"
            ],
            "type": "string",
            "description": "Duplicates are never separate rows: merged sources appear in `seenOn[]`. Probable matches are only annotated (`possibleDuplicateOf`).",
            "default": "standard"
          },
          "deltaStateStore": {
            "title": "Delta state store (optional)",
            "type": "string",
            "description": "Enable delta mode: pick a storage (KVS) you own. Only new and changed jobs are emitted and billed on later runs. Requires the lock queue below."
          },
          "deltaLockQueue": {
            "title": "Delta lock queue (required with the store)",
            "type": "string",
            "description": "An empty request queue dedicated to exactly one delta state store. Guarantees that two runs never write the same delta state at once. Two namespaces = two queues."
          },
          "trackRemovals": {
            "title": "Track removals (job-removed rows)",
            "type": "boolean",
            "description": "Delta mode only. When a tracked job disappears from every source it was seen on for removalConfirmRuns conclusive scans, emit one job-removed row (last known summary, removedAt, daysOpen, removalConfidence) and bill the job-removed event. Off by default while the false-removal soak runs; ATS boards give high-confidence removals, LinkedIn/Indeed best-effort.",
            "default": false
          },
          "removalConfirmRuns": {
            "title": "Removal confirm runs",
            "minimum": 1,
            "maximum": 10,
            "type": "integer",
            "description": "How many consecutive conclusive scans a job must be missing before job-removed is emitted. Failed, truncated or capped scans never count.",
            "default": 2
          },
          "seedFromDataset": {
            "title": "Seed delta state from a dataset (migration)",
            "type": "string",
            "description": "Migration kit: pick a dataset you already own (your own jobs-feed rows, or a LinkedIn / Indeed job-scraper export) and the FIRST run seeds the empty delta state from it - free, no rows, no events - so it emits only jobs that are actually new to you. Requires delta mode and an empty state (fresh store); ≤ 50,000 items."
          },
          "seedFormat": {
            "title": "Seed format",
            "enum": [
              "auto",
              "jobsFeed",
              "linkedinScraperCompat",
              "indeedScraperCompat"
            ],
            "type": "string",
            "description": "How to read the seed rows. Fields absent in the seed are baselined silently on the first live observation - they never trigger job-update on their own.",
            "default": "auto"
          },
          "onScopeMismatch": {
            "title": "If the delta store was built for other queries/companies",
            "enum": [
              "fail",
              "rebase"
            ],
            "type": "string",
            "description": "Delta state is bound to the exact set of queries, companies, sources and filters.",
            "default": "fail"
          },
          "onSourceError": {
            "title": "If a source fails",
            "enum": [
              "skip",
              "fail"
            ],
            "type": "string",
            "description": "`sourceHealth[]` in the run report always tells you what happened per source.",
            "default": "skip"
          },
          "maxScannedJobs": {
            "title": "Max scanned postings",
            "minimum": 1,
            "maximum": 100000,
            "type": "integer",
            "description": "Upstream cost bound: stop listing after this many postings across sources. Reported in `capsHit`.",
            "default": 20000
          },
          "maxDetailFetches": {
            "title": "Max detail-page fetches",
            "minimum": 0,
            "maximum": 50000,
            "type": "integer",
            "description": "Upstream cost bound for detail pages (descriptions, salaries). Reported in `capsHit`.",
            "default": 5000
          },
          "outputView": {
            "title": "Output view",
            "enum": [
              "jobsFeed",
              "linkedinCompat"
            ],
            "type": "string",
            "description": "Same data, two field layouts. Compat is a view over one truth.",
            "default": "jobsFeed"
          },
          "catalogMode": {
            "title": "ATS board catalog",
            "enum": [
              "auto",
              "off"
            ],
            "type": "string",
            "description": "With no companies given, the ATS sources enumerate the catalog of verified Greenhouse/Lever/Ashby boards bundled with this build (largest boards first, within maxScannedJobs) and keep the postings that match your queries. The catalog is built from public discovery only - your companies never enter it. Report field catalog shows version and boards scanned.",
            "default": "auto"
          },
          "proxyConfiguration": {
            "title": "Proxy override (advanced)",
            "type": "object",
            "description": "Bring your own proxy to reduce per-detail costs on heavy workloads. By default the guest sources (LinkedIn public, Indeed) use the built-in Apify residential proxy and ATS board APIs are fetched directly - no setup needed."
          }
        }
      },
      "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
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}