{
  "openapi": "3.0.1",
  "info": {
    "title": "Job Posting Monitor",
    "description": "Finds companies hiring for your keywords on Google Jobs (with your SerpAPI key) and free job boards. One flat Clay-ready row per posting with company domain and LinkedIn URL. Optional: the full job description, a stable posting_key, and a row when a posting closes or is reposted.",
    "version": "0.2",
    "x-build-id": "ZqTpgHHpErRZhTaf5"
  },
  "servers": [
    {
      "url": "https://api.apify.com/v2"
    }
  ],
  "paths": {
    "/acts/mambalabs~gtm-job-discovery/run-sync-get-dataset-items": {
      "post": {
        "operationId": "run-sync-get-dataset-items-mambalabs-gtm-job-discovery",
        "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/mambalabs~gtm-job-discovery/runs": {
      "post": {
        "operationId": "runs-sync-mambalabs-gtm-job-discovery",
        "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/mambalabs~gtm-job-discovery/run-sync": {
      "post": {
        "operationId": "run-sync-mambalabs-gtm-job-discovery",
        "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": [
          "keywords"
        ],
        "properties": {
          "keywords": {
            "title": "Role Keywords",
            "type": "array",
            "description": "Editorial and content role titles to search for across job boards. Matched as a phrase inside the job title or description, so keep them specific (a bare 'writer' also matches 'underwriter').",
            "items": {
              "type": "string"
            },
            "default": [
              "proofreader",
              "copy editor",
              "content editor",
              "copywriter",
              "content writer",
              "technical writer",
              "editorial",
              "content marketing",
              "content strategist"
            ]
          },
          "sources": {
            "title": "Job Board Sources",
            "type": "array",
            "description": "Which job boards to search, run as an ordered chain rather than all at once. Tier 0 needs no key and runs every keyword: Jobicy, Remotive, Arbeitnow, The Muse, Remote OK, We Work Remotely and Himalayas. Tier 1 is Adzuna (metered per call, needs an app id and key), then Indeed. Indeed is in private testing and is not yet available to public accounts; a run that lists it skips it and says so. Tier 2 runs only on keywords the earlier tiers left short: JobsPipe and TheirStack (metered per job returned) and Google Jobs through SerpAPI (metered per search). A posting that appears on two boards is deduplicated and counted once.",
            "items": {
              "type": "string",
              "enum": [
                "google_jobs",
                "jobicy",
                "remotive",
                "arbeitnow",
                "themuse",
                "remoteok",
                "weworkremotely",
                "himalayas",
                "adzuna",
                "jobspipe",
                "theirstack",
                "indeed"
              ],
              "enumTitles": [
                "Google Jobs via SerpAPI (tier 2, needs a SerpAPI key)",
                "Jobicy (tier 0, remote roles)",
                "Remotive (tier 0, remote roles)",
                "Arbeitnow (tier 0)",
                "The Muse (tier 0)",
                "Remote OK (tier 0, remote roles)",
                "We Work Remotely (tier 0, remote roles)",
                "Himalayas (tier 0, remote roles)",
                "Adzuna (tier 1, needs an app id and key)",
                "JobsPipe (tier 2, needs a key)",
                "TheirStack (tier 2, needs a key)",
                "Indeed (private testing, not yet available to public accounts)"
              ]
            },
            "default": [
              "google_jobs"
            ]
          },
          "mode": {
            "title": "Mode",
            "enum": [
              "gtm",
              "job_seeker"
            ],
            "type": "string",
            "description": "gtm (default) is the hiring signal monitor. job_seeker searches Google Jobs only around one location, skips LinkedIn resolution, keeps every posting, uses its own new posting memory, and always returns the full description. Every mode returns the same columns.",
            "default": "gtm"
          },
          "location": {
            "title": "Location (job seeker)",
            "type": "string",
            "description": "City search origin for Google Jobs, for example \"Phoenix, Arizona, United States\". Used in job_seeker mode. Ignored by remote only boards."
          },
          "radius_km": {
            "title": "Radius in km (job seeker)",
            "minimum": 1,
            "maximum": 500,
            "type": "integer",
            "description": "Search radius in kilometers, sent to Google Jobs as lrad. Google treats it as a hint and does not strictly enforce it. Used in job_seeker mode."
          },
          "employment_types": {
            "title": "Employment types",
            "type": "array",
            "description": "Keep only postings whose schedule type is one of these. A posting with no schedule type is kept. Empty means no filter.",
            "items": {
              "type": "string",
              "enum": [
                "full_time",
                "part_time",
                "contract",
                "temporary",
                "internship"
              ],
              "enumTitles": [
                "Full time",
                "Part time",
                "Contract",
                "Temporary",
                "Internship"
              ]
            }
          },
          "country": {
            "title": "Country",
            "type": "string",
            "description": "Geographic filter, e.g. United States, United Kingdom, Canada.",
            "default": "United States"
          },
          "countries": {
            "title": "Countries",
            "type": "array",
            "description": "Loop these countries inside one run. Overrides Country when set. Metered sources query each country separately; keyless remote boards are global and run once. Use the names Google Jobs accepts: United States, United Kingdom, Canada.",
            "items": {
              "type": "string"
            }
          },
          "lookback_days": {
            "title": "Lookback Days",
            "minimum": 1,
            "maximum": 365,
            "type": "integer",
            "description": "Only return postings newer than this many days.",
            "default": 30
          },
          "company_size_min": {
            "title": "Minimum Employee Count",
            "minimum": 0,
            "type": "integer",
            "description": "Optional. Drop companies with fewer employees than this (only applied when company size is known)."
          },
          "company_size_max": {
            "title": "Maximum Employee Count",
            "minimum": 0,
            "type": "integer",
            "description": "Optional. Drop companies larger than this (only applied when company size is known)."
          },
          "exclude_staffing_agencies": {
            "title": "Exclude Staffing Agencies",
            "type": "boolean",
            "description": "Filter out staffing and recruitment agency postings using name and job-description heuristics.",
            "default": true
          },
          "exclude_freelance_marketplaces": {
            "title": "Exclude Freelance Marketplaces",
            "type": "boolean",
            "description": "Filter out postings where the company is a freelance marketplace (Upwork, Fiverr, etc.), which are noise for direct outreach.",
            "default": true
          },
          "freelance_marketplaces": {
            "title": "Freelance Marketplace Names",
            "type": "array",
            "description": "Company names treated as freelance marketplaces and excluded when the toggle above is on. Defaults shown; override or extend as needed.",
            "items": {
              "type": "string"
            },
            "default": [
              "Upwork",
              "Fiverr",
              "Freelancer",
              "Toptal",
              "PeoplePerHour",
              "Guru",
              "99designs"
            ]
          },
          "remote_only": {
            "title": "Remote Only",
            "type": "boolean",
            "description": "Only return remote / work-from-home postings.",
            "default": false
          },
          "exclude_keywords": {
            "title": "Exclude keywords",
            "type": "array",
            "description": "Drop a posting when any of these terms appears in its title or description. Whole word, case insensitive; a term with spaces matches as a phrase.",
            "items": {
              "type": "string"
            }
          },
          "pages_per_keyword": {
            "title": "Google Jobs pages per keyword",
            "minimum": 1,
            "maximum": 5,
            "type": "integer",
            "description": "Pages of up to 10 results per keyword, one SerpAPI search each. Defaults to 1 in job_seeker mode. Unset in gtm mode keeps paging until max_results."
          },
          "known_job_ids": {
            "title": "Known Google job ids (job_seeker mode)",
            "type": "array",
            "description": "Google job ids you already hold. In job_seeker mode, paging for a keyword stops at the first page that brings no id outside this list and the ids already seen in the run. Ignored in gtm mode.",
            "items": {
              "type": "string"
            }
          },
          "include_full_description": {
            "title": "Include full description",
            "type": "boolean",
            "description": "Return job_description_full. Always on in job_seeker mode.",
            "default": false
          },
          "previous_run_date": {
            "title": "Previous Run Date",
            "type": "string",
            "description": "Optional ISO date (e.g. 2026-06-01) of your last run. Only postings newer than this are emitted, on top of the built-in cross-run delta cache."
          },
          "max_results": {
            "title": "Max Postings To Scan",
            "minimum": 1,
            "maximum": 500,
            "type": "integer",
            "description": "Upper bound on raw postings pulled from the discovery source before filtering. Higher values cost more.",
            "default": 100
          },
          "max_companies": {
            "title": "Max Companies To Enrich",
            "minimum": 1,
            "maximum": 200,
            "type": "integer",
            "description": "Cap on unique companies enriched per run (firmographics + LinkedIn). Bounds sub-actor cost.",
            "default": 40
          },
          "serpapi_key": {
            "title": "SerpAPI Key",
            "type": "string",
            "description": "Your own SerpAPI key for Google Jobs (get a free key at serpapi.com, 250 searches a month, no card). Google Jobs runs only when you supply it; without it the run skips Google Jobs, says so in the log and the run summary, and still runs the keyless boards you select. Stored encrypted."
          },
          "adzuna_app_id": {
            "title": "Adzuna App ID",
            "type": "string",
            "description": "Adzuna application id for the adzuna source. Your own key. Without it the adzuna source is skipped and the run says so; this actor never uses a key of its own."
          },
          "adzuna_app_key": {
            "title": "Adzuna App Key",
            "type": "string",
            "description": "Adzuna application key for the adzuna source. Your own key. Without it the adzuna source is skipped and the run says so; this actor never uses a key of its own."
          },
          "jobspipe_key": {
            "title": "JobsPipe API Key",
            "type": "string",
            "description": "JobsPipe Bearer key (jp_live_...) for the jobspipe source. Your own key. Without it the jobspipe source is skipped and the run says so; this actor never uses a key of its own. JobsPipe bills one credit per job returned."
          },
          "theirstack_key": {
            "title": "TheirStack API Key",
            "type": "string",
            "description": "TheirStack API key (a JWT) for the theirstack source. Your own key. Without it the theirstack source is skipped and the run says so; this actor never uses a key of its own. TheirStack bills one credit per job returned."
          },
          "metered_window_days": {
            "title": "Metered Date Window (days)",
            "minimum": 1,
            "maximum": 7,
            "type": "integer",
            "description": "Only ask the metered sources for postings this many days old or newer. JobsPipe and TheirStack bill per job returned, seen before or not, so a narrow window is the biggest credit saver. 1 to 7; a daily sweep wants 2.",
            "default": 2
          },
          "enough_new_companies_per_keyword": {
            "title": "Enough New Companies Per Keyword",
            "minimum": 1,
            "maximum": 100,
            "type": "integer",
            "description": "Stop the chain for a keyword once this many distinct new companies have been found for it this run. Later, metered tiers only run on keywords still below this.",
            "default": 3
          },
          "metered_run_cap": {
            "title": "Metered Run Cap",
            "minimum": 1,
            "maximum": 500,
            "type": "integer",
            "description": "Ceiling per metered source per country per run (searches for SerpAPI, calls for Adzuna, jobs for JobsPipe and TheirStack) when no quota ledger row decides a smaller one.",
            "default": 50
          },
          "indeed_countries": {
            "title": "Indeed Countries",
            "type": "array",
            "description": "Limit Indeed to these countries (names or two letter codes). Unset runs Indeed in every country in Countries that has an Indeed site. Indeed is in private testing.",
            "items": {
              "type": "string"
            }
          },
          "source_time_budgets_secs": {
            "title": "Source Time Windows (seconds)",
            "type": "object",
            "description": "Override a source's time window inside the run, for example {\"indeed\": 5}. A source that runs out of its window is retried once, then stopped, and the run moves on. Google Jobs always gets its turn. Leave empty for the defaults."
          },
          "persist_delta": {
            "title": "Remember Postings As Seen",
            "type": "boolean",
            "description": "When on, postings this run returns are remembered and not returned as new again. Turn off for a test run, so the next real run still returns them.",
            "default": true
          },
          "enrichment": {
            "title": "Enrichment",
            "type": "string",
            "description": "Internal. 'none' emits postings with the domains their sources supplied and runs no identity, firmographic or LinkedIn lookup. Unset enriches as normal."
          },
          "schedule_override_sources": {
            "title": "Schedule Override Sources",
            "type": "array",
            "description": "Metered sources that run today even when the quota ledger's weekday plan says not, for a fallback run. Every cap still applies. Applies only to runs with a quota ledger.",
            "items": {
              "type": "string"
            }
          },
          "adzuna_calls_per_minute": {
            "title": "Adzuna Calls Per Minute",
            "minimum": 1,
            "maximum": 600,
            "type": "integer",
            "description": "When set, Adzuna calls are spaced to stay at or under this many a minute across every country, a call that would start past the source's time window is not made, and an HTTP 503 is retried once. Leave empty for no spacing."
          },
          "use_gio21": {
            "title": "Use Google Jobs sub-actor fallback",
            "type": "boolean",
            "description": "Best-effort fallback to the gio21 Google Jobs sub-actor when no SerpAPI key is available. Only works on Apify plans that permit running third-party public actors.",
            "default": false
          },
          "qa_test_mode": {
            "title": "QA test mode",
            "type": "boolean",
            "description": "Internal QA fast-path. When true, the actor skips all sub-actor enrichment and emits a single summary row so automated checks complete well within the time budget. Not for normal use.",
            "default": false
          },
          "track_postings": {
            "title": "Track Postings Between Runs",
            "type": "boolean",
            "description": "When on, the actor keeps a record of the postings it returned in a named storage in your own Apify account and fills posting_key, first_seen_at, last_seen_at, and change_type. It also returns a row with change_type closed when a posting it returned before has closed, and a row with change_type reposted when a closed posting comes back. Closed and reposted rows are results and are billed like any other result row. posting_key is filled only when the company domain resolved. Off by default.",
            "default": false
          },
          "emit_closed": {
            "title": "Return Closed Postings",
            "type": "boolean",
            "description": "Read only when Track Postings is on. When on, each posting detected as closed is returned as one row with change_type closed, closed_at, closed_reason (ats_gone, missed_runs, or not_seen_days), and closed_confidence (high, medium, or low). When off, closures are still recorded but not returned.",
            "default": true
          },
          "closed_after_misses": {
            "title": "Closed After Missed Runs",
            "minimum": 1,
            "maximum": 10,
            "type": "integer",
            "description": "Read only when Track Postings is on. A posting counts as closed (missed_runs, medium confidence) after this many runs in a row that did not return it. A run counts as a miss only when every search that ever returned the posting ran and read its results to the end, so a search cut short never closes a posting.",
            "default": 2
          },
          "closed_after_days": {
            "title": "Closed After Days Not Seen",
            "minimum": 1,
            "maximum": 365,
            "type": "integer",
            "description": "Read only when Track Postings is on. A posting not seen for this many days counts as closed (not_seen_days, low confidence).",
            "default": 30
          },
          "state_key": {
            "title": "Tracking State Key",
            "type": "string",
            "description": "Read only when Track Postings is on. Names the record that holds this monitor's posting history. Leave empty to derive it from the keywords, sources, and countries, so two different monitors in one account never share history. Set it to keep history when you change the keywords."
          },
          "max_charge_usd": {
            "title": "Maximum charge for this run (USD)",
            "minimum": 0,
            "type": "number",
            "description": "Optional. The run stops before the next result that would take this run's charges over this amount, and keeps every result already charged. Leave empty to rely only on the maximum cost per run you set in Apify."
          },
          "source_tag": {
            "title": "Source Tag",
            "type": "string",
            "description": "Internal attribution tag set by Mamba Labs on published task examples. Not required, and nothing depends on it. Leave it empty."
          }
        }
      },
      "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
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}